From 5a03f7a750d4d317c3ed98d049786b40a9490467 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Mon, 26 Feb 2024 18:00:42 +0100 Subject: [PATCH 01/20] TT-916 Update TOML keys with secrets for E2E tests (#12043) * Update toml keys for secrets * Bump CTF (unreleased version) * Bump CTF * Fix go mod * Bump CTF --- .../setup-create-base64-config-live-testnets/action.yml | 4 ++-- .github/actions/setup-create-base64-config/action.yml | 4 ++-- .github/actions/setup-merge-base64-config/action.yml | 4 ++-- .github/workflows/automation-load-tests.yml | 2 +- .github/workflows/automation-ondemand-tests.yml | 2 +- .github/workflows/client-compatibility-tests.yml | 2 +- .github/workflows/integration-staging-tests.yml | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- integration-tests/testconfig/automation/example.toml | 6 +++--- integration-tests/testconfig/functions/example.toml | 6 +++--- integration-tests/testconfig/keeper/example.toml | 6 +++--- integration-tests/testconfig/log_poller/example.toml | 6 +++--- integration-tests/testconfig/node/example.toml | 6 +++--- integration-tests/testconfig/ocr/example.toml | 6 +++--- integration-tests/testconfig/ocr2/example.toml | 6 +++--- integration-tests/testconfig/vrfv2/example.toml | 6 +++--- integration-tests/testconfig/vrfv2plus/example.toml | 6 +++--- 20 files changed, 44 insertions(+), 44 deletions(-) diff --git a/.github/actions/setup-create-base64-config-live-testnets/action.yml b/.github/actions/setup-create-base64-config-live-testnets/action.yml index 5bf83191b59..89d6a5e05d6 100644 --- a/.github/actions/setup-create-base64-config-live-testnets/action.yml +++ b/.github/actions/setup-create-base64-config-live-testnets/action.yml @@ -94,7 +94,7 @@ runs: enabled=$pyroscope_enabled server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" [Logging] run_id="$RUN_ID" @@ -105,7 +105,7 @@ runs: [Logging.Loki] tenant_id="$LOKI_TENANT_ID" endpoint="$LOKI_URL" - basic_auth="$LOKI_BASIC_AUTH" + basic_auth_secret="$LOKI_BASIC_AUTH" [Logging.Grafana] base_url="$GRAFANA_URL" diff --git a/.github/actions/setup-create-base64-config/action.yml b/.github/actions/setup-create-base64-config/action.yml index 55e5924bd76..013221bb41e 100644 --- a/.github/actions/setup-create-base64-config/action.yml +++ b/.github/actions/setup-create-base64-config/action.yml @@ -96,7 +96,7 @@ runs: enabled=$pyroscope_enabled server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" [Logging] test_log_collect=$test_log_collect @@ -108,7 +108,7 @@ runs: [Logging.Loki] tenant_id="$LOKI_TENANT_ID" endpoint="$LOKI_ENDPOINT" - basic_auth="$LOKI_BASIC_AUTH" + basic_auth_secret="$LOKI_BASIC_AUTH" [Logging.Grafana] base_url="$GRAFANA_URL" diff --git a/.github/actions/setup-merge-base64-config/action.yml b/.github/actions/setup-merge-base64-config/action.yml index 9651242f8f1..d7e8d885c4f 100644 --- a/.github/actions/setup-merge-base64-config/action.yml +++ b/.github/actions/setup-merge-base64-config/action.yml @@ -42,9 +42,9 @@ runs: [Logging.Loki] tenant_id="$LOKI_TENANT_ID" endpoint="$LOKI_URL" - basic_auth="$LOKI_BASIC_AUTH" + basic_auth_secret="$LOKI_BASIC_AUTH" # legacy, you only need this to access the cloud version - # bearer_token="bearer_token" + # bearer_token_secret="bearer_token" EOF echo "$decoded_toml" >> final_config.toml diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml index bbdd59f9f5c..82a1bba6d67 100644 --- a/.github/workflows/automation-load-tests.yml +++ b/.github/workflows/automation-load-tests.yml @@ -53,7 +53,7 @@ jobs: cat << EOF > config.toml server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" EOF echo "$decoded_toml" >> final_config.toml diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 87952216d2c..b6638960aaf 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -232,7 +232,7 @@ jobs: enabled=$pyroscope_enabled server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" EOF BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 3dbcbe52cdc..214b9ff1490 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -202,7 +202,7 @@ jobs: enabled=$pyroscope_enabled server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" [PrivateEthereumNetwork] consensus_type="pos" diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml index ea0691b7ca5..6851a4ec3f1 100644 --- a/.github/workflows/integration-staging-tests.yml +++ b/.github/workflows/integration-staging-tests.yml @@ -89,7 +89,7 @@ jobs: enabled=$pyroscope_enabled server_url="$PYROSCOPE_SERVER" environment="$PYROSCOPE_ENVIRONMENT" - key="$PYROSCOPE_KEY" + key_secret="$PYROSCOPE_KEY" [Logging] run_id="$RUN_ID" @@ -100,7 +100,7 @@ jobs: [Logging.Loki] tenant_id="$LOKI_TENANT_ID" endpoint="$LOKI_URL" - basic_auth="$LOKI_BASIC_AUTH" + basic_auth_secret="$LOKI_BASIC_AUTH" [Logging.Grafana] base_url="$GRAFANA_URL" diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 955c0bbb1e5..cf3f065d812 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -24,7 +24,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c - github.com/smartcontractkit/chainlink-testing-framework v1.23.6 + github.com/smartcontractkit/chainlink-testing-framework v1.24.1 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-20240215150045-fe2ba71b2f0a diff --git a/integration-tests/go.sum b/integration-tests/go.sum index e5f34a3d982..05717c79210 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1519,8 +1519,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= -github.com/smartcontractkit/chainlink-testing-framework v1.23.6 h1:krjJswtgQ/J4kBgFpC7Tyh8wSFfWiGGUsADg6BG/EGw= -github.com/smartcontractkit/chainlink-testing-framework v1.23.6/go.mod h1:lGaqSnCB36n49fZNdTGXMrxhPu9w5+2n3c9V1Fqz1hM= +github.com/smartcontractkit/chainlink-testing-framework v1.24.1 h1:a9iBDWI6LayLFu989kt7Hadw5Y0C9K3LU+s+JIamogE= +github.com/smartcontractkit/chainlink-testing-framework v1.24.1/go.mod h1:lGaqSnCB36n49fZNdTGXMrxhPu9w5+2n3c9V1Fqz1hM= 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-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index de4360ea4e4..016d8c5c91a 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,7 +16,7 @@ require ( github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c - github.com/smartcontractkit/chainlink-testing-framework v1.23.6 + github.com/smartcontractkit/chainlink-testing-framework v1.24.1 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 github.com/smartcontractkit/libocr v0.0.0-20240215150045-fe2ba71b2f0a diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index f85521c2f7f..803c56b8d71 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1502,8 +1502,8 @@ github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= -github.com/smartcontractkit/chainlink-testing-framework v1.23.6 h1:krjJswtgQ/J4kBgFpC7Tyh8wSFfWiGGUsADg6BG/EGw= -github.com/smartcontractkit/chainlink-testing-framework v1.23.6/go.mod h1:lGaqSnCB36n49fZNdTGXMrxhPu9w5+2n3c9V1Fqz1hM= +github.com/smartcontractkit/chainlink-testing-framework v1.24.1 h1:a9iBDWI6LayLFu989kt7Hadw5Y0C9K3LU+s+JIamogE= +github.com/smartcontractkit/chainlink-testing-framework v1.24.1/go.mod h1:lGaqSnCB36n49fZNdTGXMrxhPu9w5+2n3c9V1Fqz1hM= 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= diff --git a/integration-tests/testconfig/automation/example.toml b/integration-tests/testconfig/automation/example.toml index a8e0510d83c..7a3d33951ba 100644 --- a/integration-tests/testconfig/automation/example.toml +++ b/integration-tests/testconfig/automation/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/functions/example.toml b/integration-tests/testconfig/functions/example.toml index 7628fbeee32..b96b39b0409 100644 --- a/integration-tests/testconfig/functions/example.toml +++ b/integration-tests/testconfig/functions/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use simulated network [Network] diff --git a/integration-tests/testconfig/keeper/example.toml b/integration-tests/testconfig/keeper/example.toml index 6bdd6537bc3..d76fff343e7 100644 --- a/integration-tests/testconfig/keeper/example.toml +++ b/integration-tests/testconfig/keeper/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/log_poller/example.toml b/integration-tests/testconfig/log_poller/example.toml index 90ec89a3ed1..88922e3fedb 100644 --- a/integration-tests/testconfig/log_poller/example.toml +++ b/integration-tests/testconfig/log_poller/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/node/example.toml b/integration-tests/testconfig/node/example.toml index 55ee1ffccf1..e6777bc8352 100644 --- a/integration-tests/testconfig/node/example.toml +++ b/integration-tests/testconfig/node/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/ocr/example.toml b/integration-tests/testconfig/ocr/example.toml index 6cbdbef1555..b8eb891ba33 100644 --- a/integration-tests/testconfig/ocr/example.toml +++ b/integration-tests/testconfig/ocr/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/ocr2/example.toml b/integration-tests/testconfig/ocr2/example.toml index 6cbdbef1555..b8eb891ba33 100644 --- a/integration-tests/testconfig/ocr2/example.toml +++ b/integration-tests/testconfig/ocr2/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/vrfv2/example.toml b/integration-tests/testconfig/vrfv2/example.toml index 651749486fd..53d0888f6d4 100644 --- a/integration-tests/testconfig/vrfv2/example.toml +++ b/integration-tests/testconfig/vrfv2/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] diff --git a/integration-tests/testconfig/vrfv2plus/example.toml b/integration-tests/testconfig/vrfv2plus/example.toml index 095bc06520a..2ef1c27d391 100644 --- a/integration-tests/testconfig/vrfv2plus/example.toml +++ b/integration-tests/testconfig/vrfv2plus/example.toml @@ -21,9 +21,9 @@ 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" +basic_auth_secret="loki-basic-auth" # only needed for cloud grafana -bearer_token="bearer_token" +bearer_token_secret="bearer_token" # LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) [Logging.Grafana] @@ -31,7 +31,7 @@ bearer_token="bearer_token" 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" +bearer_token_secret="my-awesome-token" # if you want to use polygon_mumbial [Network] From 02abf2ef1debedb2e023a45404706cea8c2e9a9b Mon Sep 17 00:00:00 2001 From: FelixFan1992 Date: Mon, 26 Feb 2024 14:14:42 -0500 Subject: [PATCH 02/20] AUTO-9017: polish chain modules (#12105) * AUTO-9017: polish chain modules * update overheads * update gas overheads * regen wrappers * adjust * update * prettier * udpate for arbitrum * update --- .../src/v0.8/automation/dev/chains/ArbitrumModule.sol | 4 ++-- .../src/v0.8/automation/dev/chains/ChainModuleBase.sol | 5 ++++- .../src/v0.8/automation/dev/chains/OptimismModule.sol | 8 ++++---- .../src/v0.8/automation/dev/chains/ScrollModule.sol | 10 +++++----- .../generated/arbitrum_module/arbitrum_module.go | 2 +- .../generated/chain_module_base/chain_module_base.go | 2 +- .../generated/optimism_module/optimism_module.go | 2 +- .../generated/scroll_module/scroll_module.go | 2 +- ...nerated-wrapper-dependency-versions-do-not-edit.txt | 8 ++++---- 9 files changed, 23 insertions(+), 20 deletions(-) diff --git a/contracts/src/v0.8/automation/dev/chains/ArbitrumModule.sol b/contracts/src/v0.8/automation/dev/chains/ArbitrumModule.sol index 8b79dfaaafb..b151ec8a26d 100644 --- a/contracts/src/v0.8/automation/dev/chains/ArbitrumModule.sol +++ b/contracts/src/v0.8/automation/dev/chains/ArbitrumModule.sol @@ -16,8 +16,8 @@ contract ArbitrumModule is ChainModuleBase { address private constant ARB_GAS_ADDR = 0x000000000000000000000000000000000000006C; ArbGasInfo private constant ARB_GAS = ArbGasInfo(ARB_GAS_ADDR); - uint256 private constant FIXED_GAS_OVERHEAD = 20000; - uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 20; + uint256 private constant FIXED_GAS_OVERHEAD = 5000; + uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 0; function blockHash(uint256 n) external view override returns (bytes32) { uint256 blockNum = ARB_SYS.arbBlockNumber(); diff --git a/contracts/src/v0.8/automation/dev/chains/ChainModuleBase.sol b/contracts/src/v0.8/automation/dev/chains/ChainModuleBase.sol index f7e5b7b2ab2..eccca624927 100644 --- a/contracts/src/v0.8/automation/dev/chains/ChainModuleBase.sol +++ b/contracts/src/v0.8/automation/dev/chains/ChainModuleBase.sol @@ -4,6 +4,9 @@ pragma solidity 0.8.19; import {IChainModule} from "../interfaces/v2_2/IChainModule.sol"; contract ChainModuleBase is IChainModule { + uint256 private constant FIXED_GAS_OVERHEAD = 300; + uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 0; + function blockNumber() external view virtual returns (uint256) { return block.number; } @@ -29,6 +32,6 @@ contract ChainModuleBase is IChainModule { virtual returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead) { - return (0, 0); + return (FIXED_GAS_OVERHEAD, PER_CALLDATA_BYTE_GAS_OVERHEAD); } } diff --git a/contracts/src/v0.8/automation/dev/chains/OptimismModule.sol b/contracts/src/v0.8/automation/dev/chains/OptimismModule.sol index c868deae625..1c5a3f33d1f 100644 --- a/contracts/src/v0.8/automation/dev/chains/OptimismModule.sol +++ b/contracts/src/v0.8/automation/dev/chains/OptimismModule.sol @@ -5,16 +5,16 @@ import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/v0.8.9 import {ChainModuleBase} from "./ChainModuleBase.sol"; contract OptimismModule is ChainModuleBase { - /// @dev OP_L1_DATA_FEE_PADDING includes 35 bytes for L1 data padding for Optimism and BASE + /// @dev OP_L1_DATA_FEE_PADDING includes 80 bytes for L1 data padding for Optimism and BASE bytes private constant OP_L1_DATA_FEE_PADDING = - hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; /// @dev OVM_GASPRICEORACLE_ADDR is the address of the OVM_GasPriceOracle precompile on Optimism. /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee address private constant OVM_GASPRICEORACLE_ADDR = 0x420000000000000000000000000000000000000F; OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR); - uint256 private constant FIXED_GAS_OVERHEAD = 20000; - uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 20; + uint256 private constant FIXED_GAS_OVERHEAD = 60_000; + uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 270; function getCurrentL1Fee() external view override returns (uint256) { return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(msg.data, OP_L1_DATA_FEE_PADDING)); diff --git a/contracts/src/v0.8/automation/dev/chains/ScrollModule.sol b/contracts/src/v0.8/automation/dev/chains/ScrollModule.sol index d5ea67fbc15..f01a2b537c3 100644 --- a/contracts/src/v0.8/automation/dev/chains/ScrollModule.sol +++ b/contracts/src/v0.8/automation/dev/chains/ScrollModule.sol @@ -5,18 +5,18 @@ import {IScrollL1GasPriceOracle} from "../../../vendor/@scroll-tech/contracts/sr import {ChainModuleBase} from "./ChainModuleBase.sol"; contract ScrollModule is ChainModuleBase { - /// @dev SCROLL_L1_FEE_DATA_PADDING includes 120 bytes for L1 data padding for Optimism + /// @dev SCROLL_L1_FEE_DATA_PADDING includes 140 bytes for L1 data padding for Scroll /// @dev according to testing, this padding allows automation registry to properly estimates L1 data fee with 3-5% buffer /// @dev this MAY NOT work for a different product and this may get out of date if transmit function is changed bytes private constant SCROLL_L1_FEE_DATA_PADDING = - hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; - /// @dev SCROLL_ORACLE_ADDR is the address of the L1GasPriceOracle precompile on Optimism. + hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + /// @dev SCROLL_ORACLE_ADDR is the address of the ScrollL1GasPriceOracle precompile on Scroll. /// @dev reference: https://docs.scroll.io/en/developers/transaction-fees-on-scroll/#estimating-the-l1-data-fee address private constant SCROLL_ORACLE_ADDR = 0x5300000000000000000000000000000000000002; IScrollL1GasPriceOracle private constant SCROLL_ORACLE = IScrollL1GasPriceOracle(SCROLL_ORACLE_ADDR); - uint256 private constant FIXED_GAS_OVERHEAD = 20000; - uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 20; + uint256 private constant FIXED_GAS_OVERHEAD = 45_000; + uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 170; function getCurrentL1Fee() external view override returns (uint256) { return SCROLL_ORACLE.getL1Fee(bytes.concat(msg.data, SCROLL_L1_FEE_DATA_PADDING)); diff --git a/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go b/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go index abcfd3d4bc9..8da8f57d5fa 100644 --- a/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go +++ b/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go @@ -30,7 +30,7 @@ var ( var ArbitrumModuleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50610426806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a2578063de9ee35e146100b557600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a36600461033e565b6100cb565b6040519081526020015b60405180910390f35b61007f610163565b61007f6101da565b61007f6100b036600461033e565b610228565b60408051614e2081526014602082015201610089565b600080606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801561011a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013e9190610357565b50505050915050828161015191906103d0565b61015c9060106103d0565b9392505050565b6000606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d591906103ed565b905090565b6000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b1573d6000803e3d6000fd5b600080606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029b91906103ed565b905080831015806102b657506101006102b48483610406565b115b156102c45750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061015c91906103ed565b60006020828403121561035057600080fd5b5035919050565b60008060008060008060c0878903121561037057600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176103e7576103e76103a1565b92915050565b6000602082840312156103ff57600080fd5b5051919050565b818103818111156103e7576103e76103a156fea164736f6c6343000813000a", + Bin: "0x608060405234801561001057600080fd5b50610426806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a2578063de9ee35e146100b557600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a36600461033e565b6100cb565b6040519081526020015b60405180910390f35b61007f610163565b61007f6101da565b61007f6100b036600461033e565b610228565b6040805161138881526000602082015201610089565b600080606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801561011a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013e9190610357565b50505050915050828161015191906103d0565b61015c9060106103d0565b9392505050565b6000606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d591906103ed565b905090565b6000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b1573d6000803e3d6000fd5b600080606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029b91906103ed565b905080831015806102b657506101006102b48483610406565b115b156102c45750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061015c91906103ed565b60006020828403121561035057600080fd5b5035919050565b60008060008060008060c0878903121561037057600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176103e7576103e76103a1565b92915050565b6000602082840312156103ff57600080fd5b5051919050565b818103818111156103e7576103e76103a156fea164736f6c6343000813000a", } var ArbitrumModuleABI = ArbitrumModuleMetaData.ABI diff --git a/core/gethwrappers/generated/chain_module_base/chain_module_base.go b/core/gethwrappers/generated/chain_module_base/chain_module_base.go index 4c830566ef5..bf98608aab7 100644 --- a/core/gethwrappers/generated/chain_module_base/chain_module_base.go +++ b/core/gethwrappers/generated/chain_module_base/chain_module_base.go @@ -30,7 +30,7 @@ var ( var ChainModuleBaseMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061015a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610093575b600080fd5b61008061007a3660046100f4565b50600090565b6040519081526020015b60405180910390f35b6000610080565b43610080565b6100806100ae3660046100f4565b6100c7565b60408051600080825260208201520161008a565b600043821015806100e257506101006100e0834361010d565b115b156100ef57506000919050565b504090565b60006020828403121561010657600080fd5b5035919050565b81810381811115610147577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000a", + Bin: "0x608060405234801561001057600080fd5b5061015c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610093575b600080fd5b61008061007a3660046100f6565b50600090565b6040519081526020015b60405180910390f35b6000610080565b43610080565b6100806100ae3660046100f6565b6100c9565b6040805161012c8152600060208201520161008a565b600043821015806100e457506101006100e2834361010f565b115b156100f157506000919050565b504090565b60006020828403121561010857600080fd5b5035919050565b81810381811115610149577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000a", } var ChainModuleBaseABI = ChainModuleBaseMetaData.ABI diff --git a/core/gethwrappers/generated/optimism_module/optimism_module.go b/core/gethwrappers/generated/optimism_module/optimism_module.go index c6015b1e32b..009ab6d8cff 100644 --- a/core/gethwrappers/generated/optimism_module/optimism_module.go +++ b/core/gethwrappers/generated/optimism_module/optimism_module.go @@ -30,7 +30,7 @@ var ( var OptimismModuleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506104a3806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e8565b6100c9565b6040519081526020015b60405180910390f35b61007f6101ea565b4361007f565b61007f6100ae3660046102e8565b6102bb565b60408051614e2081526014602082015201610089565b6000806100d7836004610330565b67ffffffffffffffff8111156100ef576100ef61034d565b6040519080825280601f01601f191660200182016040528015610119576020820181803683370190505b50905073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e82604051806060016040528060238152602001610474602391396040516020016101779291906103a0565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a291906103cf565b602060405180830381865afa1580156101bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e39190610420565b9392505050565b600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060600160405280602381526020016104746023913960405160200161024a93929190610439565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027591906103cf565b602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190610420565b905090565b600043821015806102d657506101006102d48343610460565b115b156102e357506000919050565b504090565b6000602082840312156102fa57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034757610347610301565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b8381101561039757818101518382015260200161037f565b50506000910152565b600083516103b281846020880161037c565b8351908301906103c681836020880161037c565b01949350505050565b60208152600082518060208401526103ee81604085016020870161037c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043257600080fd5b5051919050565b82848237600083820160008152835161045681836020880161037c565b0195945050505050565b818103818111156103475761034761030156feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a", + Bin: "0x608060405234801561001057600080fd5b506104d1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e9565b6100ca565b6040519081526020015b60405180910390f35b61007f6101eb565b4361007f565b61007f6100ae3660046102e9565b6102bc565b6040805161ea60815261010e602082015201610089565b6000806100d8836004610331565b67ffffffffffffffff8111156100f0576100f061034e565b6040519080825280601f01601f19166020018201604052801561011a576020820181803683370190505b50905073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e82604051806080016040528060508152602001610475605091396040516020016101789291906103a1565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a391906103d0565b602060405180830381865afa1580156101c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e49190610421565b9392505050565b600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060800160405280605081526020016104756050913960405160200161024b9392919061043a565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027691906103d0565b602060405180830381865afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b79190610421565b905090565b600043821015806102d757506101006102d58343610461565b115b156102e457506000919050565b504090565b6000602082840312156102fb57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034857610348610302565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b83811015610398578181015183820152602001610380565b50506000910152565b600083516103b381846020880161037d565b8351908301906103c781836020880161037d565b01949350505050565b60208152600082518060208401526103ef81604085016020870161037d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043357600080fd5b5051919050565b82848237600083820160008152835161045781836020880161037d565b0195945050505050565b818103818111156103485761034861030256feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a", } var OptimismModuleABI = OptimismModuleMetaData.ABI diff --git a/core/gethwrappers/generated/scroll_module/scroll_module.go b/core/gethwrappers/generated/scroll_module/scroll_module.go index 2bb37a8d480..702cc39a7ae 100644 --- a/core/gethwrappers/generated/scroll_module/scroll_module.go +++ b/core/gethwrappers/generated/scroll_module/scroll_module.go @@ -30,7 +30,7 @@ var ( var ScrollModuleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506104f8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e8565b6100c9565b6040519081526020015b60405180910390f35b61007f6101ea565b4361007f565b61007f6100ae3660046102e8565b6102bb565b60408051614e2081526014602082015201610089565b6000806100d7836004610330565b67ffffffffffffffff8111156100ef576100ef61034d565b6040519080825280601f01601f191660200182016040528015610119576020820181803683370190505b50905073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e826040518060a0016040528060788152602001610474607891396040516020016101779291906103a0565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a291906103cf565b602060405180830381865afa1580156101bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e39190610420565b9392505050565b600073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060a00160405280607881526020016104746078913960405160200161024a93929190610439565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027591906103cf565b602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190610420565b905090565b600043821015806102d657506101006102d48343610460565b115b156102e357506000919050565b504090565b6000602082840312156102fa57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034757610347610301565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b8381101561039757818101518382015260200161037f565b50506000910152565b600083516103b281846020880161037c565b8351908301906103c681836020880161037c565b01949350505050565b60208152600082518060208401526103ee81604085016020870161037c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043257600080fd5b5051919050565b82848237600083820160008152835161045681836020880161037c565b0195945050505050565b818103818111156103475761034761030156feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a", + Bin: "0x608060405234801561001057600080fd5b5061050c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e8565b6100c9565b6040519081526020015b60405180910390f35b61007f6101ea565b4361007f565b61007f6100ae3660046102e8565b6102bb565b6040805161afc8815260aa602082015201610089565b6000806100d7836004610330565b67ffffffffffffffff8111156100ef576100ef61034d565b6040519080825280601f01601f191660200182016040528015610119576020820181803683370190505b50905073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e826040518060c00160405280608c8152602001610474608c91396040516020016101779291906103a0565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a291906103cf565b602060405180830381865afa1580156101bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e39190610420565b9392505050565b600073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060c00160405280608c8152602001610474608c913960405160200161024a93929190610439565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027591906103cf565b602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190610420565b905090565b600043821015806102d657506101006102d48343610460565b115b156102e357506000919050565b504090565b6000602082840312156102fa57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034757610347610301565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b8381101561039757818101518382015260200161037f565b50506000910152565b600083516103b281846020880161037c565b8351908301906103c681836020880161037c565b01949350505050565b60208152600082518060208401526103ee81604085016020870161037c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043257600080fd5b5051919050565b82848237600083820160008152835161045681836020880161037c565b0195945050505050565b818103818111156103475761034761030156feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a", } var ScrollModuleABI = ScrollModuleMetaData.ABI 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 88c5c2ebdd6..96eaf97c2d7 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,7 +1,7 @@ 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 -arbitrum_module: ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.abi ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.bin 9048e5ccf9a6274cbf131cb5d7ef24b783e2fc9595153e0abacddfd2b6668469 +arbitrum_module: ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.abi ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.bin 9615cb0e524e6ca87e86e1714420c08d4de6f6407bfb5546da04ac7dea7f9107 authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e @@ -17,7 +17,7 @@ batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBloc 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 73cb626b5cb2c3464655b61b8ac42fe7a1963fe25e6a5eea40b8e4d5bff3de36 blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e -chain_module_base: ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin 41331cdf20464ea860ab57324642ff4797feb20e376908921726ce7e5cb2cf34 +chain_module_base: ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin 39dfce79330e921e5c169051b11c6e5ea15cd4db5a7b09c06aabbe9658148915 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 @@ -58,10 +58,10 @@ multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer/MultiWord 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 357203fabe3df436eb015e2d5094374c6967a9fc922ac8edc265b27aac4d67cf operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin c5e1db81070d940a82ef100b0bce38e055593cbeebbc73abf9d45c30d6020cd2 -optimism_module: ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.abi ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.bin 7df8460e07edd0cc849f7e7b111a4135d9e4740ad8fb25003d6a21dc2b6ffe25 +optimism_module: ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.abi ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.bin a1f8ee97e12b1b2311db03b94dc52b91f3c2e9a2f8d554031a9c7b41e4432280 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 -scroll_module: ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.abi ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.bin c7283da6f6bd4874f8c5b2d6fb93fd1d9dfbab30d0f39adf5c9d448d88acdb88 +scroll_module: ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.abi ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.bin 8de157cb7e5bc78146548212803d60926c8483aca7e912d802b7c66dc5d2ab11 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 From b9f577db625ee21cd5e4ec143fa41bd404ecce21 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Mon, 26 Feb 2024 13:45:53 -0800 Subject: [PATCH 03/20] chore: dependabot github action version bumps (#12101) * Bump actions/setup-node from 4.0.1 to 4.0.2 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8...60edb5dd545a775178f52524783378180af0d1f8) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump aws-actions/configure-aws-credentials from 4.0.1 to 4.0.2 Bumps [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/010d0da01d0b5a38af31e9c3470dbfdabdecca3a...e3dd6a429d7300a6a4c196c26e071d42e0343502) --- updated-dependencies: - dependency-name: aws-actions/configure-aws-credentials dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump golangci/golangci-lint-action from 3.7.0 to 4.0.0 Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.7.0 to 4.0.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/3a919529898de77ec3da873e3063ca4b10e7f5cc...3cfe3a4abbb849e10058ce4af15d205b6da42804) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump peter-evans/create-pull-request from 5.0.2 to 6.0.0 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/153407881ec5c347639a548ade7d8ad1d6740e38...b1ddad2c994a25fbc81a28b3ec0e368bb2021c50) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump reviewdog/action-actionlint from 1.39.1 to 1.41.0 Bumps [reviewdog/action-actionlint](https://github.com/reviewdog/action-actionlint) from 1.39.1 to 1.41.0. - [Release notes](https://github.com/reviewdog/action-actionlint/releases) - [Commits](https://github.com/reviewdog/action-actionlint/compare/82693e9e3b239f213108d6e412506f8b54003586...6a38513dd4d2e818798c5c73d0870adbb82de4a4) --- updated-dependencies: - dependency-name: reviewdog/action-actionlint dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump slackapi/slack-github-action from 1.24.0 to 1.25.0 Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.24.0 to 1.25.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/e28cf165c92ffef168d23c5c9000cffc8a25e117...6c661ce58804a1a20f6dc5fbee7f0381b469e001) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: chainchad <96362174+chainchad@users.noreply.github.com> --- .github/workflows/automation-nightly-tests.yml | 4 ++-- .github/workflows/ci-core.yml | 8 ++++---- .github/workflows/client-compatibility-tests.yml | 2 +- .github/workflows/goreleaser-build-publish-develop.yml | 4 ++-- .github/workflows/helm-chart-publish.yml | 2 +- .github/workflows/integration-tests-publish.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- .github/workflows/lint-gh-workflows.yml | 2 +- .github/workflows/live-testnet-tests.yml | 2 +- .github/workflows/operator-ui-cd.yml | 4 ++-- .github/workflows/operator-ui-ci.yml | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml index 81d9606ef17..83551bd2e6b 100644 --- a/.github/workflows/automation-nightly-tests.yml +++ b/.github/workflows/automation-nightly-tests.yml @@ -147,7 +147,7 @@ jobs: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} - name: Main Slack Notification - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 id: slack with: channel-id: C03KJ5S7KEK @@ -245,7 +245,7 @@ jobs: echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT - name: Test Details - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 with: channel-id: C03KJ5S7KEK payload: | diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 01938679054..9f43918d27e 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -30,7 +30,7 @@ jobs: gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} - name: Notify Slack if: ${{ failure() && (github.event_name == 'merge_group' || github.event.branch == 'develop')}} - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} with: @@ -50,7 +50,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -122,7 +122,7 @@ jobs: ./postgres_logs.txt - name: Notify Slack if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.event.branch == 'develop') }} - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} with: @@ -151,7 +151,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 214b9ff1490..3b752746c44 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -258,7 +258,7 @@ jobs: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} - name: Main Slack Notification - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 id: slack with: channel-id: ${{ secrets.QA_SLACK_CHANNEL }} diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml index 5d4041bbc47..a7a0fd0bbf6 100644 --- a/.github/workflows/goreleaser-build-publish-develop.yml +++ b/.github/workflows/goreleaser-build-publish-develop.yml @@ -20,7 +20,7 @@ jobs: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} @@ -59,7 +59,7 @@ jobs: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_GATI }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} diff --git a/.github/workflows/helm-chart-publish.yml b/.github/workflows/helm-chart-publish.yml index 156268d66b0..ca0ff6104a4 100644 --- a/.github/workflows/helm-chart-publish.yml +++ b/.github/workflows/helm-chart-publish.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Configure aws credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_GATI }} role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index 79f5013044e..71105c93d71 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -48,7 +48,7 @@ jobs: - name: Notify Slack # Only run this notification for merge to develop failures if: failure() && github.event_name != 'workflow_dispatch' - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} with: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 45401b3cd63..812c10535b2 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -110,7 +110,7 @@ jobs: go build ./... go test -run=^# ./... - name: Lint Go - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: version: v1.55.2 # We already cache these directories in setup-go diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index 1d546905a76..381a2a56e16 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -9,7 +9,7 @@ jobs: - name: Check out Code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run actionlint - uses: reviewdog/action-actionlint@82693e9e3b239f213108d6e412506f8b54003586 # v1.39.1 + uses: reviewdog/action-actionlint@6a38513dd4d2e818798c5c73d0870adbb82de4a4 # v1.41.0 - name: Collect Metrics if: always() id: collect-gha-metrics diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index 9cb980aca6c..b5b47382d72 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -122,7 +122,7 @@ jobs: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} - name: Main Slack Notification - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 id: slack with: channel-id: ${{ secrets.QA_SLACK_CHANNEL }} diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml index d2d6d96471c..7bbdc3deaef 100644 --- a/.github/workflows/operator-ui-cd.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -25,7 +25,7 @@ jobs: run: ./operator_ui/check.sh - name: Assume role capable of dispatching action - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_AUTO_PR_TOKEN_ISSUER_ROLE_ARN }} role-duration-seconds: ${{ secrets.aws-role-duration-seconds }} @@ -39,7 +39,7 @@ jobs: url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} - name: Open PR - uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 + uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 # v6.0.0 with: title: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} token: ${{ steps.get-gh-token.outputs.access-token }} diff --git a/.github/workflows/operator-ui-ci.yml b/.github/workflows/operator-ui-ci.yml index 2ce85bc1322..6e1a5e76033 100644 --- a/.github/workflows/operator-ui-ci.yml +++ b/.github/workflows/operator-ui-ci.yml @@ -23,7 +23,7 @@ jobs: continue-on-error: true - name: Assume role capable of dispatching action - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_OPERATOR_UI_ACCESS_TOKEN_ISSUER_ROLE_ARN }} role-duration-seconds: 3600 From 64df78e146c98b90532fec19d4896bfdf3a80a83 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 26 Feb 2024 18:40:14 -0500 Subject: [PATCH 04/20] Wiring context for EVM Keys API (#11800) * feature/sql-tracing: adding tracing to our db * XSAM otelsql library * WIP: understanding context prop * WIP, wiring ctx through from keys eth create works * WIP, wiring CTX through all keys eth APIs * WIP: borked a rebase * linting + cleanup * disabling context-check from linters * further cleanup * updating tests with hardcoded mock arguments * updating mocks * fixing test from rebase * runLoop now uses context from stop channel * updating runLoop in resender to use internal context * wiring context through ServiceForSpec in the job.Delegate interface * updating common/txmgr/tracker to use background context internally and parent context for tracker state * cleans up some dangling contexts, consistency with use of c.Request.Context() in web routes, and marks TODOs where needed * cleaning up context.Background's in tests * cleaning up use of *cli.Context instead of Request.Context() --- common/txmgr/broadcaster.go | 2 +- common/txmgr/confirmer.go | 10 +- common/txmgr/resender.go | 10 +- common/txmgr/test_helpers.go | 4 +- common/txmgr/tracker.go | 14 +- common/txmgr/txmgr.go | 27 +- common/txmgr/types/client.go | 2 +- common/txmgr/types/keystore.go | 8 +- common/txmgr/types/mocks/key_store.go | 48 +-- .../txmgr/types/mocks/tx_attempt_builder.go | 40 +- common/txmgr/types/tx_attempt_builder.go | 4 +- core/chains/evm/monitor/balance.go | 2 +- core/chains/evm/txmgr/attempts.go | 36 +- core/chains/evm/txmgr/attempts_test.go | 34 +- core/chains/evm/txmgr/broadcaster_test.go | 14 +- core/chains/evm/txmgr/client.go | 4 +- core/chains/evm/txmgr/confirmer_test.go | 55 ++- core/chains/evm/txmgr/evm_tx_store_test.go | 4 +- core/chains/evm/txmgr/resender_test.go | 3 +- core/chains/evm/txmgr/txmgr_test.go | 6 +- core/chains/evm/types/models_test.go | 2 +- core/cmd/eth_keys_commands_test.go | 18 +- core/cmd/ocr2vrf_configure_commands.go | 16 +- core/cmd/shell_local.go | 4 +- core/cmd/shell_local_test.go | 5 +- core/internal/cltest/cltest.go | 11 +- core/internal/cltest/factories.go | 12 +- core/internal/features/features_test.go | 11 +- .../features/ocr2/features_ocr2_test.go | 2 +- .../chaincli/handler/keeper_upkeep_history.go | 6 +- core/services/blockhashstore/bhs.go | 6 +- core/services/blockhashstore/bhs_test.go | 7 +- core/services/blockhashstore/delegate.go | 4 +- core/services/blockhashstore/delegate_test.go | 15 +- .../blockheaderfeeder/block_header_feeder.go | 2 +- .../block_header_feeder_test.go | 4 +- core/services/blockheaderfeeder/delegate.go | 10 +- core/services/cron/cron_test.go | 2 +- core/services/cron/delegate.go | 4 +- core/services/directrequest/delegate.go | 2 +- core/services/directrequest/delegate_test.go | 6 +- .../fluxmonitorv2/contract_submitter.go | 2 +- .../fluxmonitorv2/contract_submitter_test.go | 2 +- core/services/fluxmonitorv2/delegate.go | 4 +- core/services/fluxmonitorv2/flux_monitor.go | 7 +- .../fluxmonitorv2/flux_monitor_test.go | 30 +- core/services/fluxmonitorv2/key_store.go | 5 +- core/services/fluxmonitorv2/key_store_test.go | 13 +- .../mocks/key_store_interface.go | 38 +- core/services/gateway/delegate.go | 3 +- core/services/job/job_orm_test.go | 25 +- core/services/job/orm.go | 18 +- core/services/job/runner_integration_test.go | 10 +- core/services/job/spawner.go | 6 +- core/services/job/spawner_test.go | 3 +- core/services/keeper/delegate.go | 4 +- core/services/keeper/upkeep_executer_test.go | 5 +- core/services/keystore/eth.go | 119 +++--- core/services/keystore/eth_test.go | 350 ++++++++++-------- core/services/keystore/mocks/eth.go | 332 +++++++++-------- core/services/ocr/delegate.go | 3 +- core/services/ocr2/delegate.go | 10 +- .../v1/internal/testutils.go | 2 +- .../services/ocr2/plugins/functions/plugin.go | 9 +- .../ocr2/plugins/functions/plugin_test.go | 15 +- .../internal/ocr2vrf_integration_test.go | 23 +- core/services/ocrbootstrap/delegate.go | 4 +- core/services/ocrcommon/transmitter.go | 4 +- core/services/pipeline/task.eth_tx.go | 4 +- core/services/pipeline/task.eth_tx_test.go | 22 +- core/services/relay/evm/evm.go | 21 +- core/services/relay/evm/functions.go | 8 +- core/services/relay/evm/ocr2keeper.go | 6 +- core/services/relay/evm/ocr2vrf.go | 13 +- core/services/streams/delegate.go | 2 +- core/services/streams/delegate_test.go | 5 +- core/services/vrf/delegate.go | 11 +- core/services/vrf/delegate_test.go | 14 +- core/services/vrf/v2/integration_v2_test.go | 4 +- .../vrf/v2/listener_v2_log_processor.go | 4 +- core/services/vrf/v2/listener_v2_test.go | 8 +- core/services/vrf/v2/reverted_txns.go | 2 +- core/services/vrf/vrfcommon/types.go | 3 +- core/services/webhook/delegate.go | 2 +- core/services/webhook/delegate_test.go | 13 +- core/services/workflows/delegate.go | 3 +- core/services/workflows/engine_test.go | 3 +- core/web/eth_keys_controller.go | 30 +- core/web/eth_keys_controller_test.go | 2 +- core/web/resolver/eth_key_test.go | 42 +-- core/web/resolver/query.go | 6 +- 91 files changed, 934 insertions(+), 816 deletions(-) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 4c59a950ac1..3e7520aff1a 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -208,7 +208,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star return errors.New("Broadcaster is already started") } var err error - eb.enabledAddresses, err = eb.ks.EnabledAddressesForChain(eb.chainID) + eb.enabledAddresses, err = eb.ks.EnabledAddressesForChain(ctx, eb.chainID) if err != nil { return fmt.Errorf("Broadcaster: failed to load EnabledAddressesForChain: %w", err) } diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index c28216467a1..073a6b90fa4 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -183,7 +183,7 @@ func NewConfirmer[ } // Start is a comment to appease the linter -func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(_ context.Context) error { +func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx context.Context) error { return ec.StartOnce("Confirmer", func() error { if ec.feeConfig.BumpThreshold() == 0 { ec.lggr.Infow("Gas bumping is disabled (FeeEstimator.BumpThreshold set to 0)", "feeBumpThreshold", 0) @@ -191,18 +191,18 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Sta ec.lggr.Infow(fmt.Sprintf("Fee bumping is enabled, unconfirmed transactions will have their fee bumped every %d blocks", ec.feeConfig.BumpThreshold()), "feeBumpThreshold", ec.feeConfig.BumpThreshold()) } - return ec.startInternal() + return ec.startInternal(ctx) }) } -func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal() error { +func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal(ctx context.Context) error { ec.initSync.Lock() defer ec.initSync.Unlock() if ec.isStarted { return errors.New("Confirmer is already started") } var err error - ec.enabledAddresses, err = ec.ks.EnabledAddressesForChain(ec.chainID) + ec.enabledAddresses, err = ec.ks.EnabledAddressesForChain(ctx, ec.chainID) if err != nil { return fmt.Errorf("Confirmer: failed to load EnabledAddressesForChain: %w", err) } @@ -1065,7 +1065,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For if overrideGasLimit != 0 { etx.FeeLimit = overrideGasLimit } - attempt, _, err := ec.NewCustomTxAttempt(*etx, fee, etx.FeeLimit, 0x0, ec.lggr) + attempt, _, err := ec.NewCustomTxAttempt(ctx, *etx, fee, etx.FeeLimit, 0x0, ec.lggr) if err != nil { ec.lggr.Errorw("ForceRebroadcast: failed to create new attempt", "txID", etx.ID, "err", err) continue diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 384c0c7a2c0..8c2dd6b827e 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -102,7 +102,7 @@ func NewResender[ } // Start is a comment which satisfies the linter -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start() { +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx context.Context) { er.logger.Debugf("Enabled with poll interval of %s and age threshold of %s", er.interval, er.txConfig.ResendAfterThreshold()) go er.runLoop() } @@ -116,7 +116,7 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Stop() { func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { defer close(er.chDone) - if err := er.resendUnconfirmed(); err != nil { + if err := er.resendUnconfirmed(er.ctx); err != nil { er.logger.Warnw("Failed to resend unconfirmed transactions", "err", err) } @@ -127,15 +127,15 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() case <-er.ctx.Done(): return case <-ticker.C: - if err := er.resendUnconfirmed(); err != nil { + if err := er.resendUnconfirmed(er.ctx); err != nil { er.logger.Warnw("Failed to resend unconfirmed transactions", "err", err) } } } } -func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) resendUnconfirmed() error { - resendAddresses, err := er.ks.EnabledAddressesForChain(er.chainID) +func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) resendUnconfirmed(ctx context.Context) error { + resendAddresses, err := er.ks.EnabledAddressesForChain(ctx, er.chainID) if err != nil { return fmt.Errorf("Resender failed getting enabled keys for chain %s: %w", er.chainID.String(), err) } diff --git a/common/txmgr/test_helpers.go b/common/txmgr/test_helpers.go index 6c0c5680ea7..dbc07861ffe 100644 --- a/common/txmgr/test_helpers.go +++ b/common/txmgr/test_helpers.go @@ -35,7 +35,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) XXXT } func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestStartInternal() error { - return ec.startInternal() + return ec.startInternal(ec.ctx) } func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestCloseInternal() error { @@ -43,7 +43,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXX } func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestResendUnconfirmed() error { - return er.resendUnconfirmed() + return er.resendUnconfirmed(er.ctx) } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) XXXTestAbandon(addr ADDR) (err error) { diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go index 8b66668c41e..c63d9c264fc 100644 --- a/common/txmgr/tracker.go +++ b/common/txmgr/tracker.go @@ -91,25 +91,25 @@ func NewTracker[ } } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(_ context.Context) (err error) { +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx context.Context) (err error) { tr.lggr.Info("Abandoned transaction tracking enabled") return tr.StartOnce("Tracker", func() error { - return tr.startInternal() + return tr.startInternal(ctx) }) } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal() (err error) { +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) startInternal(ctx context.Context) (err error) { tr.lock.Lock() defer tr.lock.Unlock() tr.ctx, tr.ctxCancel = context.WithCancel(context.Background()) - if err := tr.setEnabledAddresses(); err != nil { + if err := tr.setEnabledAddresses(ctx); err != nil { return fmt.Errorf("failed to set enabled addresses: %w", err) } tr.lggr.Info("Enabled addresses set") - if err := tr.trackAbandonedTxes(tr.ctx); err != nil { + if err := tr.trackAbandonedTxes(ctx); err != nil { return fmt.Errorf("failed to track abandoned txes: %w", err) } @@ -194,8 +194,8 @@ func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsStarted() return tr.isStarted } -func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) setEnabledAddresses() error { - enabledAddrs, err := tr.keyStore.EnabledAddressesForChain(tr.chainID) +func (tr *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) setEnabledAddresses(ctx context.Context) error { + enabledAddrs, err := tr.keyStore.EnabledAddressesForChain(ctx, tr.chainID) if err != nil { return fmt.Errorf("failed to get enabled addresses for chain: %w", err) } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 3e3fa9a20db..d0b33ad7e30 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -209,7 +209,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx } if b.resender != nil { - b.resender.Start() + b.resender.Start(ctx) } if b.fwdMgr != nil { @@ -308,10 +308,13 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HealthRepo } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { + ctx, cancel := b.chStop.NewCtx() + defer cancel() + // eb, ec and keyStates can all be modified by the runloop. // This is concurrent-safe because the runloop ensures serial access. defer b.wg.Done() - keysChanged, unsub := b.keyStore.SubscribeToKeyChanges() + keysChanged, unsub := b.keyStore.SubscribeToKeyChanges(ctx) defer unsub() close(b.chSubbed) @@ -321,7 +324,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() // execReset is defined as an inline function here because it closes over // eb, ec and stopped - execReset := func(r *reset) { + execReset := func(ctx context.Context, r *reset) { // These should always close successfully, since it should be logically // impossible to enter this code path with ec/eb in a state other than // "Started" @@ -348,8 +351,6 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() wg.Add(2) go func() { defer wg.Done() - ctx, cancel := b.chStop.NewCtx() - defer cancel() // Retry indefinitely on failure backoff := iutils.NewRedialBackoff() for { @@ -361,7 +362,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() continue } return - case <-ctx.Done(): + case <-b.chStop: stopOnce.Do(func() { stopped = true }) return } @@ -374,7 +375,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() for { select { case <-time.After(backoff.Duration()): - if err := b.confirmer.startInternal(); err != nil { + if err := b.confirmer.startInternal(ctx); err != nil { b.logger.Criticalw("Failed to start Confirmer", "err", err) b.SvcErrBuffer.Append(err) continue @@ -408,7 +409,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() reset.done <- errors.New("Txm was stopped") continue } - execReset(&reset) + execReset(ctx, &reset) case <-b.chStop: // close and exit // @@ -441,7 +442,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() if stopped { continue } - enabledAddresses, err := b.keyStore.EnabledAddressesForChain(b.chainID) + enabledAddresses, err := b.keyStore.EnabledAddressesForChain(ctx, b.chainID) if err != nil { b.logger.Critical("Failed to reload key states after key change") b.SvcErrBuffer.Append(err) @@ -449,7 +450,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() } b.logger.Debugw("Keys changed, reloading", "enabledAddresses", enabledAddresses) - execReset(nil) + execReset(ctx, nil) } } } @@ -496,7 +497,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTran } } - if err = b.checkEnabled(txRequest.FromAddress); err != nil { + if err = b.checkEnabled(ctx, txRequest.FromAddress); err != nil { return tx, err } @@ -543,8 +544,8 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForward return } -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabled(addr ADDR) error { - if err := b.keyStore.CheckEnabled(addr, b.chainID); err != nil { +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabled(ctx context.Context, addr ADDR) error { + if err := b.keyStore.CheckEnabled(ctx, addr, b.chainID); err != nil { return fmt.Errorf("cannot send transaction from %s on chain ID %s: %w", addr, b.chainID.String(), err) } return nil diff --git a/common/txmgr/types/client.go b/common/txmgr/types/client.go index 0db50e97ad3..32527e5896e 100644 --- a/common/txmgr/types/client.go +++ b/common/txmgr/types/client.go @@ -62,7 +62,7 @@ type TransactionClient[ ) (client.SendTxReturnCode, error) SendEmptyTransaction( ctx context.Context, - newTxAttempt func(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error), + newTxAttempt func(ctx context.Context, seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error), seq SEQ, gasLimit uint32, fee FEE, diff --git a/common/txmgr/types/keystore.go b/common/txmgr/types/keystore.go index 9c5b8cfce37..0eecc49be70 100644 --- a/common/txmgr/types/keystore.go +++ b/common/txmgr/types/keystore.go @@ -1,6 +1,8 @@ package types import ( + "context" + "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -15,7 +17,7 @@ type KeyStore[ // Chain's sequence type. For example, EVM chains use nonce, bitcoin uses UTXO. SEQ types.Sequence, ] interface { - CheckEnabled(address ADDR, chainID CHAIN_ID) error - EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) - SubscribeToKeyChanges() (ch chan struct{}, unsub func()) + CheckEnabled(ctx context.Context, address ADDR, chainID CHAIN_ID) error + EnabledAddressesForChain(ctx context.Context, chainId CHAIN_ID) ([]ADDR, error) + SubscribeToKeyChanges(ctx context.Context) (ch chan struct{}, unsub func()) } diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index d440528a41d..7e825322977 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -3,6 +3,8 @@ package mocks import ( + context "context" + mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/common/types" @@ -13,17 +15,17 @@ type KeyStore[ADDR types.Hashable, CHAIN_ID types.ID, SEQ types.Sequence] struct mock.Mock } -// CheckEnabled provides a mock function with given fields: address, chainID -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAIN_ID) error { - ret := _m.Called(address, chainID) +// CheckEnabled provides a mock function with given fields: ctx, address, chainID +func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(ctx context.Context, address ADDR, chainID CHAIN_ID) error { + ret := _m.Called(ctx, 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) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r0 = rf(ctx, address, chainID) } else { r0 = ret.Error(0) } @@ -31,9 +33,9 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAI return r0 } -// EnabledAddressesForChain provides a mock function with given fields: chainId -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) { - ret := _m.Called(chainId) +// EnabledAddressesForChain provides a mock function with given fields: ctx, chainId +func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx context.Context, chainId CHAIN_ID) ([]ADDR, error) { + ret := _m.Called(ctx, chainId) if len(ret) == 0 { panic("no return value specified for EnabledAddressesForChain") @@ -41,19 +43,19 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ var r0 []ADDR var r1 error - if rf, ok := ret.Get(0).(func(CHAIN_ID) ([]ADDR, error)); ok { - return rf(chainId) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]ADDR, error)); ok { + return rf(ctx, chainId) } - if rf, ok := ret.Get(0).(func(CHAIN_ID) []ADDR); ok { - r0 = rf(chainId) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []ADDR); ok { + r0 = rf(ctx, chainId) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ADDR) } } - if rf, ok := ret.Get(1).(func(CHAIN_ID) error); ok { - r1 = rf(chainId) + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainId) } else { r1 = ret.Error(1) } @@ -61,9 +63,9 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ return r0, r1 } -// SubscribeToKeyChanges provides a mock function with given fields: -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, func()) { - ret := _m.Called() +// SubscribeToKeyChanges provides a mock function with given fields: ctx +func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for SubscribeToKeyChanges") @@ -71,19 +73,19 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, var r0 chan struct{} var r1 func() - if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (chan struct{}, func())); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() chan struct{}); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) chan struct{}); ok { + r0 = rf(ctx) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(chan struct{}) } } - if rf, ok := ret.Get(1).(func() func()); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) func()); ok { + r1 = rf(ctx) } else { if ret.Get(1) != nil { r1 = ret.Get(1).(func()) diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index b3b6ff761fb..5b9b3e505ad 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -125,9 +125,9 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) return r0, r1, r2, r3, r4 } -// NewCustomTxAttempt provides a mock function with given fields: tx, fee, gasLimit, txType, lggr -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) +// NewCustomTxAttempt provides a mock function with given fields: ctx, tx, fee, gasLimit, txType, lggr +func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewCustomTxAttempt(ctx context.Context, 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(ctx, tx, fee, gasLimit, txType, lggr) if len(ret) == 0 { panic("no return value specified for NewCustomTxAttempt") @@ -136,23 +136,23 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bool, error)); ok { - return rf(tx, fee, gasLimit, txType, lggr) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bool, error)); ok { + return rf(ctx, tx, fee, gasLimit, txType, lggr) } - if rf, ok := ret.Get(0).(func(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(tx, fee, gasLimit, txType, lggr) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, tx, fee, gasLimit, txType, lggr) } else { r0 = ret.Get(0).(txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) bool); ok { - r1 = rf(tx, fee, gasLimit, txType, lggr) + if rf, ok := ret.Get(1).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) bool); ok { + r1 = rf(ctx, tx, fee, gasLimit, txType, lggr) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) error); ok { - r2 = rf(tx, fee, gasLimit, txType, lggr) + if rf, ok := ret.Get(2).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, int, logger.Logger) error); ok { + r2 = rf(ctx, tx, fee, gasLimit, txType, lggr) } else { r2 = ret.Error(2) } @@ -160,9 +160,9 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) return r0, r1, r2 } -// NewEmptyTxAttempt provides a mock function with given fields: seq, feeLimit, fee, fromAddress -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) +// NewEmptyTxAttempt provides a mock function with given fields: ctx, seq, feeLimit, fee, fromAddress +func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewEmptyTxAttempt(ctx context.Context, seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, seq, feeLimit, fee, fromAddress) if len(ret) == 0 { panic("no return value specified for NewEmptyTxAttempt") @@ -170,17 +170,17 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(SEQ, uint32, FEE, ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(seq, feeLimit, fee, fromAddress) + if rf, ok := ret.Get(0).(func(context.Context, SEQ, uint32, FEE, ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, seq, feeLimit, fee, fromAddress) } - if rf, ok := ret.Get(0).(func(SEQ, uint32, FEE, ADDR) txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(seq, feeLimit, fee, fromAddress) + if rf, ok := ret.Get(0).(func(context.Context, SEQ, uint32, FEE, ADDR) txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, seq, feeLimit, fee, fromAddress) } else { r0 = ret.Get(0).(txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(SEQ, uint32, FEE, ADDR) error); ok { - r1 = rf(seq, feeLimit, fee, fromAddress) + if rf, ok := ret.Get(1).(func(context.Context, SEQ, uint32, FEE, ADDR) error); ok { + r1 = rf(ctx, seq, feeLimit, fee, fromAddress) } else { r1 = ret.Error(1) } diff --git a/common/txmgr/types/tx_attempt_builder.go b/common/txmgr/types/tx_attempt_builder.go index 383b6d862f0..47c71abea35 100644 --- a/common/txmgr/types/tx_attempt_builder.go +++ b/common/txmgr/types/tx_attempt_builder.go @@ -37,8 +37,8 @@ type TxAttemptBuilder[ NewBumpTxAttempt(ctx context.Context, tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], previousAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], priorAttempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], lggr logger.Logger) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bumpedFee FEE, bumpedFeeLimit uint32, retryable bool, err error) // NewCustomTxAttempt builds a transaction using the passed in fee + tx type - NewCustomTxAttempt(tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fee FEE, gasLimit uint32, txType int, lggr logger.Logger) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], retryable bool, err error) + NewCustomTxAttempt(ctx context.Context, tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fee FEE, gasLimit uint32, txType int, lggr logger.Logger) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], retryable bool, err error) // NewEmptyTxAttempt is used in ForceRebroadcast to create a signed tx with zero value sent to the zero address - NewEmptyTxAttempt(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + NewEmptyTxAttempt(ctx context.Context, seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) } diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index b0f0fbc9c91..bb271ad1d46 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -174,7 +174,7 @@ func (w *worker) Work() { } func (w *worker) WorkCtx(ctx context.Context) { - enabledAddresses, err := w.bm.ethKeyStore.EnabledAddressesForChain(w.bm.chainID) + enabledAddresses, err := w.bm.ethKeyStore.EnabledAddressesForChain(ctx, w.bm.chainID) if err != nil { w.bm.logger.Error("BalanceMonitor: error getting keys", err) } diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index 91645bae6f6..e37f0e4d2d8 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -20,7 +20,7 @@ import ( ) type TxAttemptSigner[ADDR commontypes.Hashable] interface { - SignTx(fromAddress ADDR, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) + SignTx(ctx context.Context, fromAddress ADDR, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) } var _ TxAttemptBuilder = (*evmTxAttemptBuilder)(nil) @@ -62,7 +62,7 @@ func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx, return attempt, fee, feeLimit, true, errors.Wrap(err, "failed to get fee") // estimator errors are retryable } - attempt, retryable, err = c.NewCustomTxAttempt(etx, fee, feeLimit, txType, lggr) + attempt, retryable, err = c.NewCustomTxAttempt(ctx, etx, fee, feeLimit, txType, lggr) return attempt, fee, feeLimit, retryable, err } @@ -76,13 +76,13 @@ func (c *evmTxAttemptBuilder) NewBumpTxAttempt(ctx context.Context, etx Tx, prev return attempt, bumpedFee, bumpedFeeLimit, true, errors.Wrap(err, "failed to bump fee") // estimator errors are retryable } - attempt, retryable, err = c.NewCustomTxAttempt(etx, bumpedFee, bumpedFeeLimit, previousAttempt.TxType, lggr) + attempt, retryable, err = c.NewCustomTxAttempt(ctx, etx, bumpedFee, bumpedFeeLimit, previousAttempt.TxType, lggr) return attempt, bumpedFee, bumpedFeeLimit, retryable, err } // NewCustomTxAttempt is the lowest level func where the fee parameters + tx type must be passed in // used in the txm for force rebroadcast where fees and tx type are pre-determined without an estimator -func (c *evmTxAttemptBuilder) NewCustomTxAttempt(etx Tx, fee gas.EvmFee, gasLimit uint32, txType int, lggr logger.Logger) (attempt TxAttempt, retryable bool, err error) { +func (c *evmTxAttemptBuilder) NewCustomTxAttempt(ctx context.Context, etx Tx, fee gas.EvmFee, gasLimit uint32, txType int, lggr logger.Logger) (attempt TxAttempt, retryable bool, err error) { switch txType { case 0x0: // legacy if fee.Legacy == nil { @@ -90,7 +90,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(etx Tx, fee gas.EvmFee, gasLimi logger.Sugared(lggr).AssumptionViolation(err.Error()) return attempt, false, err // not retryable } - attempt, err = c.newLegacyAttempt(etx, fee.Legacy, gasLimit) + attempt, err = c.newLegacyAttempt(ctx, etx, fee.Legacy, gasLimit) return attempt, true, err case 0x2: // dynamic, EIP1559 if !fee.ValidDynamic() { @@ -98,7 +98,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(etx Tx, fee gas.EvmFee, gasLimi logger.Sugared(lggr).AssumptionViolation(err.Error()) return attempt, false, err // not retryable } - attempt, err = c.newDynamicFeeAttempt(etx, gas.DynamicFee{ + attempt, err = c.newDynamicFeeAttempt(ctx, etx, gas.DynamicFee{ FeeCap: fee.DynamicFeeCap, TipCap: fee.DynamicTipCap, }, gasLimit) @@ -112,7 +112,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(etx Tx, fee gas.EvmFee, gasLimi } // NewEmptyTxAttempt is used in ForceRebroadcast to create a signed tx with zero value sent to the zero address -func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit uint32, fee gas.EvmFee, fromAddress common.Address) (attempt TxAttempt, err error) { +func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(ctx context.Context, nonce evmtypes.Nonce, feeLimit uint32, fee gas.EvmFee, fromAddress common.Address) (attempt TxAttempt, err error) { value := big.NewInt(0) payload := []byte{} @@ -130,7 +130,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit u ) transaction := types.NewTx(&tx) - hash, signedTxBytes, err := c.SignTx(fromAddress, transaction) + hash, signedTxBytes, err := c.SignTx(ctx, fromAddress, transaction) if err != nil { return attempt, errors.Wrapf(err, "error using account %s to sign empty transaction", fromAddress.String()) } @@ -141,7 +141,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit u } -func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(etx Tx, fee gas.DynamicFee, gasLimit uint32) (attempt TxAttempt, err error) { +func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(ctx context.Context, etx Tx, fee gas.DynamicFee, gasLimit uint32) (attempt TxAttempt, err error) { if err = validateDynamicFeeGas(c.feeConfig, c.feeConfig.TipCapMin(), fee, gasLimit, etx); err != nil { return attempt, errors.Wrap(err, "error validating gas") } @@ -157,7 +157,7 @@ func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(etx Tx, fee gas.DynamicFee, g etx.EncodedPayload, ) tx := types.NewTx(&d) - attempt, err = c.newSignedAttempt(etx, tx) + attempt, err = c.newSignedAttempt(ctx, etx, tx) if err != nil { return attempt, err } @@ -226,8 +226,8 @@ func newDynamicFeeTransaction(nonce uint64, to common.Address, value *big.Int, g } } -func (c *evmTxAttemptBuilder) newLegacyAttempt(etx Tx, gasPrice *assets.Wei, gasLimit uint32) (attempt TxAttempt, err error) { - if err = validateLegacyGas(c.feeConfig, c.feeConfig.PriceMin(), gasPrice, gasLimit, etx); err != nil { +func (c *evmTxAttemptBuilder) newLegacyAttempt(ctx context.Context, etx Tx, gasPrice *assets.Wei, gasLimit uint32) (attempt TxAttempt, err error) { + if err = validateLegacyGas(ctx, c.feeConfig, c.feeConfig.PriceMin(), gasPrice, gasLimit, etx); err != nil { return attempt, errors.Wrap(err, "error validating gas") } @@ -241,7 +241,7 @@ func (c *evmTxAttemptBuilder) newLegacyAttempt(etx Tx, gasPrice *assets.Wei, gas ) transaction := types.NewTx(&tx) - hash, signedTxBytes, err := c.SignTx(etx.FromAddress, transaction) + hash, signedTxBytes, err := c.SignTx(ctx, etx.FromAddress, transaction) if err != nil { return attempt, errors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress, etx.ID) } @@ -260,7 +260,7 @@ func (c *evmTxAttemptBuilder) newLegacyAttempt(etx Tx, gasPrice *assets.Wei, gas // validateLegacyGas is a sanity check - we have other checks elsewhere, but this // makes sure we _never_ create an invalid attempt -func validateLegacyGas(kse keySpecificEstimator, minGasPriceWei, gasPrice *assets.Wei, gasLimit uint32, etx Tx) error { +func validateLegacyGas(ctx context.Context, kse keySpecificEstimator, minGasPriceWei, gasPrice *assets.Wei, gasLimit uint32, etx Tx) error { if gasPrice == nil { panic("gas price missing") } @@ -275,8 +275,8 @@ func validateLegacyGas(kse keySpecificEstimator, minGasPriceWei, gasPrice *asset return nil } -func (c *evmTxAttemptBuilder) newSignedAttempt(etx Tx, tx *types.Transaction) (attempt TxAttempt, err error) { - hash, signedTxBytes, err := c.SignTx(etx.FromAddress, tx) +func (c *evmTxAttemptBuilder) newSignedAttempt(ctx context.Context, etx Tx, tx *types.Transaction) (attempt TxAttempt, err error) { + hash, signedTxBytes, err := c.SignTx(ctx, etx.FromAddress, tx) if err != nil { return attempt, errors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress.String(), etx.ID) } @@ -301,8 +301,8 @@ 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) +func (c *evmTxAttemptBuilder) SignTx(ctx context.Context, address common.Address, tx *types.Transaction) (common.Hash, []byte, error) { + signedTx, err := c.keystore.SignTx(ctx, address, tx, &c.chainID) if err != nil { return common.Hash{}, nil, fmt.Errorf("failed to sign tx: %w", err) } diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index c7373e2c4f6..e0b3cd59ce7 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -68,9 +68,9 @@ func TestTxm_SignTx(t *testing.T) { t.Run("returns correct hash for non-okex chains", func(t *testing.T) { chainID := big.NewInt(1) kst := ksmocks.NewEth(t) - kst.On("SignTx", to, tx, chainID).Return(tx, nil).Once() + kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) - hash, rawBytes, err := cks.SignTx(addr, tx) + hash, rawBytes, err := cks.SignTx(testutils.Context(t), addr, tx) require.NoError(t, err) require.NotNil(t, rawBytes) require.Equal(t, "0xdd68f554373fdea7ec6713a6e437e7646465d553a6aa0b43233093366cc87ef0", hash.String()) @@ -79,9 +79,9 @@ func TestTxm_SignTx(t *testing.T) { t.Run("returns correct hash for okex chains", func(t *testing.T) { chainID := big.NewInt(1) kst := ksmocks.NewEth(t) - kst.On("SignTx", to, tx, chainID).Return(tx, nil).Once() + kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) - hash, rawBytes, err := cks.SignTx(addr, tx) + hash, rawBytes, err := cks.SignTx(testutils.Context(t), addr, tx) require.NoError(t, err) require.NotNil(t, rawBytes) require.Equal(t, "0xdd68f554373fdea7ec6713a6e437e7646465d553a6aa0b43233093366cc87ef0", hash.String()) @@ -89,10 +89,10 @@ func TestTxm_SignTx(t *testing.T) { 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() + kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) - _, rawBytes, err := cks.SignTx(addr, tx) + _, rawBytes, err := cks.SignTx(testutils.Context(t), addr, tx) require.NoError(t, err) require.NotNil(t, rawBytes) require.Equal(t, "0xe42a82015681f294b921f7763960b296b9cbad586ff066a18d749724818e83010203808080", hexutil.Encode(rawBytes)) @@ -112,9 +112,9 @@ func TestTxm_SignTx(t *testing.T) { Gas: 242, Data: []byte{1, 2, 3}, }) - kst.On("SignTx", to, typedTx, chainID).Return(typedTx, nil).Once() + kst.On("SignTx", mock.Anything, to, typedTx, chainID).Return(typedTx, nil).Once() cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) - _, rawBytes, err := cks.SignTx(addr, typedTx) + _, rawBytes, err := cks.SignTx(testutils.Context(t), addr, typedTx) require.NoError(t, err) require.NotNil(t, rawBytes) require.Equal(t, "0xa702e5802a808081f294b921f7763960b296b9cbad586ff066a18d749724818e83010203c0808080", hexutil.Encode(rawBytes)) @@ -130,7 +130,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { addr := NewEvmAddress() tx := types.NewTx(&types.DynamicFeeTx{}) kst := ksmocks.NewEth(t) - kst.On("SignTx", addr, mock.Anything, big.NewInt(1)).Return(tx, nil) + kst.On("SignTx", mock.Anything, addr, mock.Anything, big.NewInt(1)).Return(tx, nil) var n evmtypes.Nonce lggr := logger.Test(t) @@ -139,7 +139,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { feeCfg.priceMax = assets.GWei(200) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), feeCfg, kst, nil) dynamicFee := gas.DynamicFee{TipCap: assets.GWei(100), FeeCap: assets.GWei(200)} - a, _, err := cks.NewCustomTxAttempt(txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ + a, _, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ DynamicTipCap: dynamicFee.TipCap, DynamicFeeCap: dynamicFee.FeeCap, }, 100, 0x2, lggr) @@ -181,7 +181,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg.EVM().GasEstimator(), kst, nil) dynamicFee := gas.DynamicFee{TipCap: test.tipcap, FeeCap: test.feecap} - _, _, err := cks.NewCustomTxAttempt(txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ + _, _, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ DynamicTipCap: dynamicFee.TipCap, DynamicFeeCap: dynamicFee.FeeCap, }, 100, 0x2, lggr) @@ -199,7 +199,7 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { addr := NewEvmAddress() kst := ksmocks.NewEth(t) tx := types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", addr, mock.Anything, big.NewInt(1)).Return(tx, nil) + kst.On("SignTx", mock.Anything, addr, mock.Anything, big.NewInt(1)).Return(tx, nil) gc := newFeeConfig() gc.priceMin = assets.NewWeiI(10) gc.priceMax = assets.NewWeiI(50) @@ -208,7 +208,7 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { t.Run("creates attempt with fields", func(t *testing.T) { var n evmtypes.Nonce - a, _, err := cks.NewCustomTxAttempt(txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{Legacy: assets.NewWeiI(25)}, 100, 0x0, lggr) + a, _, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{Legacy: assets.NewWeiI(25)}, 100, 0x0, lggr) require.NoError(t, err) assert.Equal(t, 100, int(a.ChainSpecificFeeLimit)) assert.NotNil(t, a.TxFee.Legacy) @@ -218,7 +218,7 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { }) t.Run("verifies max gas price", func(t *testing.T) { - _, _, err := cks.NewCustomTxAttempt(txmgr.Tx{FromAddress: addr}, gas.EvmFee{Legacy: assets.NewWeiI(100)}, 100, 0x0, lggr) + _, _, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{FromAddress: addr}, gas.EvmFee{Legacy: assets.NewWeiI(100)}, 100, 0x0, lggr) require.Error(t, err) assert.Contains(t, err.Error(), fmt.Sprintf("specified gas price of 100 wei would exceed max configured gas price of 50 wei for key %s", addr.String())) }) @@ -235,7 +235,7 @@ func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { legacyFee := assets.NewWeiI(100) t.Run("dynamic fee with legacy tx type", func(t *testing.T) { - _, retryable, err := cks.NewCustomTxAttempt(txmgr.Tx{}, gas.EvmFee{ + _, retryable, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{}, gas.EvmFee{ DynamicTipCap: dynamicFee.TipCap, DynamicFeeCap: dynamicFee.FeeCap, }, 100, 0x0, lggr) @@ -243,13 +243,13 @@ func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { assert.False(t, retryable) }) t.Run("legacy fee with dynamic tx type", func(t *testing.T) { - _, retryable, err := cks.NewCustomTxAttempt(txmgr.Tx{}, gas.EvmFee{Legacy: legacyFee}, 100, 0x2, lggr) + _, retryable, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{}, gas.EvmFee{Legacy: legacyFee}, 100, 0x2, lggr) require.Error(t, err) assert.False(t, retryable) }) t.Run("invalid type", func(t *testing.T) { - _, retryable, err := cks.NewCustomTxAttempt(txmgr.Tx{}, gas.EvmFee{}, 100, 0xA, lggr) + _, retryable, err := cks.NewCustomTxAttempt(testutils.Context(t), txmgr.Tx{}, gas.EvmFee{}, 100, 0xA, lggr) require.Error(t, err) assert.False(t, retryable) }) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 67e9b0d8f04..2af22d76a66 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -1648,7 +1648,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) ctx := testutils.Context(t) @@ -1658,7 +1658,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { t.Run("tx signing fails", func(t *testing.T) { etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) tx := *gethTypes.NewTx(&gethTypes.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.AnythingOfType("*types.Transaction"), mock.MatchedBy(func(chainID *big.Int) bool { @@ -1696,7 +1696,7 @@ func TestEthBroadcaster_GetNextNonce(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) nonce := getLocalNextNonce(t, eb, fromAddress) @@ -1714,7 +1714,7 @@ func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) @@ -1777,7 +1777,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() 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, nil, lggr, checkerFactory, false) err := eb.Start(ctx) @@ -1795,7 +1795,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() 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) @@ -1824,7 +1824,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index 0aa03536276..e794f56ba31 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -145,7 +145,7 @@ func (c *evmTxmClient) BatchGetReceipts(ctx context.Context, attempts []TxAttemp // May be useful for clearing stuck nonces func (c *evmTxmClient) SendEmptyTransaction( ctx context.Context, - newTxAttempt func(seq evmtypes.Nonce, feeLimit uint32, fee gas.EvmFee, fromAddress common.Address) (attempt TxAttempt, err error), + newTxAttempt func(ctx context.Context, seq evmtypes.Nonce, feeLimit uint32, fee gas.EvmFee, fromAddress common.Address) (attempt TxAttempt, err error), seq evmtypes.Nonce, gasLimit uint32, fee gas.EvmFee, @@ -153,7 +153,7 @@ func (c *evmTxmClient) SendEmptyTransaction( ) (txhash string, err error) { defer utils.WrapIfError(&err, "sendEmptyTransaction failed") - attempt, err := newTxAttempt(seq, gasLimit, fee, fromAddress) + attempt, err := newTxAttempt(ctx, seq, gasLimit, fee, fromAddress) if err != nil { return txhash, err } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 6cb14a8d618..1860b557335 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -1646,7 +1646,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing 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() + kst.On("EnabledAddressesForChain", mock.Anything, &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) servicetest.Run(t, ec) @@ -1693,7 +1693,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing 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() + kst.On("EnabledAddressesForChain", mock.Anything, &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) servicetest.Run(t, ec) currentHead := int64(30) @@ -1738,7 +1738,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) @@ -1753,7 +1753,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { t.Run("treats an exceeds max fee attempt as a success", func(t *testing.T) { ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if tx.Nonce() != uint64(*etx.Sequence) { @@ -1805,7 +1805,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) @@ -1825,7 +1825,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("re-sends previous transaction on keystore error", func(t *testing.T) { // simulate bumped transaction that is somehow impossible to sign - kst.On("SignTx", fromAddress, + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) }), @@ -1845,7 +1845,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing and continues on fatal error", func(t *testing.T) { ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if tx.Nonce() != uint64(*etx.Sequence) { @@ -1879,7 +1879,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -1927,7 +1927,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_2.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx.Sequence || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -1966,7 +1966,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethTx := *types.NewTx(&types.LegacyTx{}) receipt := evmtypes.Receipt{BlockNumber: big.NewInt(40)} - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx.Sequence || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2013,13 +2013,13 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt2_1.ID)) var attempt2_2 txmgr.TxAttempt - t.Run("saves in_progress attempt on temporary error and returns error", func(t *testing.T) { + t.Run("saves in-progress attempt on temporary error and returns error", func(t *testing.T) { expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt2_1.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) n := *etx2.Sequence - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != n || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2086,7 +2086,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethTx := *types.NewTx(&types.LegacyTx{}) n := *etx2.Sequence - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != n || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2127,7 +2127,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedGasPrice.Int64(), attempt3_1.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx3.Sequence || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2164,7 +2164,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedGasPrice.Int64(), attempt3_1.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx3.Sequence || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2203,7 +2203,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedGasPrice.Int64(), attempt3_2.TxFee.Legacy.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx3.Sequence || expectedBumpedGasPrice.Cmp(tx.GasPrice()) != 0 { @@ -2299,7 +2299,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("EIP-1559: bumps using EIP-1559 rules when existing attempts are of type 0x2", func(t *testing.T) { ethTx := *types.NewTx(&types.DynamicFeeTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx4.Sequence { @@ -2367,7 +2367,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Greater(t, expectedBumpedTipCap.Int64(), attempt4_2.TxFee.DynamicTipCap.ToInt().Int64()) ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", + kst.On("SignTx", mock.Anything, fromAddress, mock.MatchedBy(func(tx *types.Transaction) bool { if evmtypes.Nonce(tx.Nonce()) != *etx4.Sequence || expectedBumpedTipCap.ToInt().Cmp(tx.GasTipCap()) != 0 { @@ -2417,7 +2417,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Use a mock keystore for this test kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() currentHead := int64(30) oldEnough := 5 nonce := int64(0) @@ -2440,7 +2440,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( commonclient.Successful, nil).Once() - kst.On("SignTx", mock.Anything, mock.Anything, mock.Anything).Return( + kst.On("SignTx", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return( signedTx, nil, ).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) @@ -2464,14 +2464,14 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( commonclient.Successful, nil).Once() signedLegacyTx := new(types.Transaction) - kst.On("SignTx", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { + kst.On("SignTx", mock.Anything, mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Type() == 0x0 && tx.Nonce() == uint64(*etx.Sequence) }), mock.Anything).Return( signedLegacyTx, nil, ).Run(func(args mock.Arguments) { - unsignedLegacyTx := args.Get(1).(*types.Transaction) + unsignedLegacyTx := args.Get(2).(*types.Transaction) // Use the real keystore to do the actual signing - thisSignedLegacyTx, err := ethKeyStore.SignTx(fromAddress, unsignedLegacyTx, testutils.FixtureChainID) + thisSignedLegacyTx, err := ethKeyStore.SignTx(testutils.Context(t), fromAddress, unsignedLegacyTx, testutils.FixtureChainID) require.NoError(t, err) *signedLegacyTx = *thisSignedLegacyTx }).Times(4) // 3 failures 1 success @@ -2496,14 +2496,14 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( commonclient.Successful, nil).Once() signedDxFeeTx := new(types.Transaction) - kst.On("SignTx", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { + kst.On("SignTx", mock.Anything, mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Type() == 0x2 && tx.Nonce() == uint64(*etx.Sequence) }), mock.Anything).Return( signedDxFeeTx, nil, ).Run(func(args mock.Arguments) { - unsignedDxFeeTx := args.Get(1).(*types.Transaction) + unsignedDxFeeTx := args.Get(2).(*types.Transaction) // Use the real keystore to do the actual signing - thisSignedDxFeeTx, err := ethKeyStore.SignTx(fromAddress, unsignedDxFeeTx, testutils.FixtureChainID) + thisSignedDxFeeTx, err := ethKeyStore.SignTx(testutils.Context(t), fromAddress, unsignedDxFeeTx, testutils.FixtureChainID) require.NoError(t, err) *signedDxFeeTx = *thisSignedDxFeeTx }).Times(4) // 3 failures 1 success @@ -2513,7 +2513,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -2523,7 +2522,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - _, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) + _, err := ethKeyStore.EnabledKeysForChain(testutils.Context(t), testutils.FixtureChainID) require.NoError(t, err) require.NoError(t, err) // keyStates, err := ethKeyStore.GetStatesForKeys(keys) diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 1e478e09b58..0994268037f 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -411,8 +411,8 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { }) t.Run("only updates evm.tx_attempts for the current chain", func(t *testing.T) { - require.NoError(t, ethKeyStore.Add(fromAddress, testutils.SimulatedChainID)) - require.NoError(t, ethKeyStore.Enable(fromAddress, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Add(testutils.Context(t), fromAddress, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Enable(testutils.Context(t), fromAddress, testutils.SimulatedChainID)) etxThisChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress, cfg.EVM().ChainID()) etxOtherChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress, testutils.SimulatedChainID) diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index fd3d1745010..e8c1c9e079f 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -155,6 +155,7 @@ func Test_EthResender_Start(t *testing.T) { lggr := logger.Test(t) t.Run("resends transactions that have been languishing unconfirmed for too long", func(t *testing.T) { + ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTracker(txStore, ethKeyStore, big.NewInt(0), lggr), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) @@ -180,7 +181,7 @@ func Test_EthResender_Start(t *testing.T) { }) func() { - er.Start() + er.Start(ctx) defer er.Stop() cltest.EventuallyExpectationsMet(t, ethClient, 5*time.Second, time.Second) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 85e37571b5a..8e4a59bc099 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -481,11 +481,11 @@ func TestTxm_Lifecycle(t *testing.T) { evmConfig.ReaperThreshold = 1 * time.Hour evmConfig.ReaperInterval = 1 * time.Hour - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return([]common.Address{}, nil) + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return([]common.Address{}, nil) keyChangeCh := make(chan struct{}) unsub := cltest.NewAwaiter() - kst.On("SubscribeToKeyChanges").Return(keyChangeCh, unsub.ItHappened) + kst.On("SubscribeToKeyChanges", mock.Anything).Return(keyChangeCh, unsub.ItHappened) estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst) require.NoError(t, err) @@ -506,7 +506,7 @@ func TestTxm_Lifecycle(t *testing.T) { keyState := cltest.MustGenerateRandomKeyState(t) addr := []common.Address{keyState.Address.Address()} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addr, nil) + kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addr, nil) ethClient.On("PendingNonceAt", mock.AnythingOfType("*context.cancelCtx"), common.Address{}).Return(uint64(0), nil).Maybe() keyChangeCh <- struct{}{} diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 7617b45f9a0..f2f58c3a983 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -99,7 +99,7 @@ func TestEthTxAttempt_GetSignedTx(t *testing.T) { chainID := big.NewInt(3) - signedTx, err := ethKeyStore.SignTx(fromAddress, tx, chainID) + signedTx, err := ethKeyStore.SignTx(testutils.Context(t), fromAddress, tx, chainID) require.NoError(t, err) rlp := new(bytes.Buffer) require.NoError(t, signedTx.EncodeRLP(rlp)) diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index de40a5bf873..2f22cd1d3ae 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -148,7 +148,7 @@ func TestShell_ListETHKeys_Disabled(t *testing.T) { withMocks(ethClient), ) client, r := app.NewShellAndRenderer() - keys, err := app.KeyStore.Eth().GetAll() + keys, err := app.KeyStore.Eth().GetAll(testutils.Context(t)) require.NoError(t, err) require.Equal(t, 1, len(keys)) k := keys[0] @@ -186,7 +186,7 @@ func TestShell_CreateETHKey(t *testing.T) { client, _ := app.NewShellAndRenderer() cltest.AssertCount(t, db, "evm.key_states", 1) // The initial funding key - keys, err := app.KeyStore.Eth().GetAll() + keys, err := app.KeyStore.Eth().GetAll(testutils.Context(t)) require.NoError(t, err) require.Equal(t, 1, len(keys)) @@ -202,7 +202,7 @@ func TestShell_CreateETHKey(t *testing.T) { assert.NoError(t, client.CreateETHKey(c)) cltest.AssertCount(t, db, "evm.key_states", 2) - keys, err = app.KeyStore.Eth().GetAll() + keys, err = app.KeyStore.Eth().GetAll(testutils.Context(t)) require.NoError(t, err) require.Equal(t, 2, len(keys)) } @@ -221,7 +221,7 @@ func TestShell_DeleteETHKey(t *testing.T) { client, _ := app.NewShellAndRenderer() // Create the key - key, err := ethKeyStore.Create(&cltest.FixtureChainID) + key, err := ethKeyStore.Create(testutils.Context(t), &cltest.FixtureChainID) require.NoError(t, err) // Delete the key @@ -235,7 +235,7 @@ func TestShell_DeleteETHKey(t *testing.T) { err = client.DeleteETHKey(c) require.NoError(t, err) - _, err = ethKeyStore.Get(key.Address.Hex()) + _, err = ethKeyStore.Get(testutils.Context(t), key.Address.Hex()) assert.Error(t, err) } @@ -303,7 +303,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { c = cli.NewContext(nil, set, nil) err = client.DeleteETHKey(c) require.NoError(t, err) - _, err = ethKeyStore.Get(address) + _, err = ethKeyStore.Get(testutils.Context(t), address) require.Error(t, err) cltest.AssertCount(t, app.GetSqlxDB(), "evm.key_states", 0) @@ -328,7 +328,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { err = client.ListETHKeys(c) require.NoError(t, err) require.Len(t, *r.Renders[0].(*cmd.EthKeyPresenters), 1) - _, err = ethKeyStore.Get(address) + _, err = ethKeyStore.Get(testutils.Context(t), address) require.NoError(t, err) // Export test invalid id @@ -411,7 +411,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { c = cli.NewContext(nil, set, nil) err = client.DeleteETHKey(c) require.NoError(t, err) - _, err = ethKeyStore.Get(address) + _, err = ethKeyStore.Get(testutils.Context(t), address) require.Error(t, err) // Import the key @@ -435,7 +435,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { err = client.ListETHKeys(c) require.NoError(t, err) require.Len(t, *r.Renders[0].(*cmd.EthKeyPresenters), 1) - _, err = ethKeyStore.Get(address) + _, err = ethKeyStore.Get(testutils.Context(t), address) require.NoError(t, err) // Export test invalid id diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index 06f26ddb6a4..906c27374c8 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -173,7 +173,7 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e // Initialize keystore and generate keys. keyStore := app.GetKeyStore() - err = setupKeystore(s, app, keyStore) + err = setupKeystore(ctx, s, app, keyStore) if err != nil { return nil, s.errorOut(err) } @@ -191,7 +191,7 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e var sendingKeys []string var sendingKeysAddresses []common.Address useForwarder := c.Bool("use-forwarder") - ethKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(big.NewInt(chainID)) + ethKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(ctx, big.NewInt(chainID)) if err != nil { return nil, s.errorOut(err) } @@ -205,7 +205,7 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e if useForwarder { // Add extra sending keys if using a forwarder. - sendingKeys, sendingKeysAddresses, err = s.appendForwarders(chainID, app.GetKeyStore().Eth(), sendingKeys, sendingKeysAddresses) + sendingKeys, sendingKeysAddresses, err = s.appendForwarders(ctx, chainID, app.GetKeyStore().Eth(), sendingKeys, sendingKeysAddresses) if err != nil { return nil, err } @@ -298,16 +298,16 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e }, nil } -func (s *Shell) appendForwarders(chainID int64, ks keystore.Eth, sendingKeys []string, sendingKeysAddresses []common.Address) ([]string, []common.Address, error) { +func (s *Shell) appendForwarders(ctx context.Context, chainID int64, ks keystore.Eth, sendingKeys []string, sendingKeysAddresses []common.Address) ([]string, []common.Address, error) { for i := 0; i < forwarderAdditionalEOACount; i++ { // Create the sending key in the keystore. - k, err := ks.Create() + k, err := ks.Create(ctx) if err != nil { return nil, nil, err } // Enable the sending key for the current chain. - err = ks.Enable(k.Address, big.NewInt(chainID)) + err = ks.Enable(ctx, k.Address, big.NewInt(chainID)) if err != nil { return nil, nil, err } @@ -351,7 +351,7 @@ func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logg return nil } -func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Master) error { +func setupKeystore(ctx context.Context, cli *Shell, app chainlink.Application, keyStore keystore.Master) error { if err := cli.KeyStoreAuthenticator.authenticate(keyStore, cli.Config.Password()); err != nil { return errors.Wrap(err, "error authenticating keystore") } @@ -362,7 +362,7 @@ func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Mast return fmt.Errorf("failed to get legacy evm chains") } for _, ch := range chains { - if err = keyStore.Eth().EnsureKeys(ch.ID()); err != nil { + if err = keyStore.Eth().EnsureKeys(ctx, ch.ID()); err != nil { return errors.Wrap(err, "failed to ensure keystore keys") } } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 350e6abf77d..7e03fe719e1 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -378,7 +378,7 @@ func (s *Shell) runNode(c *cli.Context) error { for _, ch := range chainList { if ch.Config().EVM().AutoCreateKey() { lggr.Debugf("AutoCreateKey=true, will ensure EVM key for chain %s", ch.ID()) - err2 := app.GetKeyStore().Eth().EnsureKeys(ch.ID()) + err2 := app.GetKeyStore().Eth().EnsureKeys(rootCtx, ch.ID()) if err2 != nil { return errors.Wrap(err2, "failed to ensure keystore keys") } @@ -625,7 +625,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { return s.errorOut(errors.Wrap(err, "error authenticating keystore")) } - if err = keyStore.Eth().CheckEnabled(address, chain.ID()); err != nil { + if err = keyStore.Eth().CheckEnabled(ctx, address, chain.ID()); err != nil { return s.errorOut(err) } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 72c2f2b5bbd..d6f4946dd9d 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -181,7 +181,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { pgtest.MustExec(t, db, "DELETE FROM users;") keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - _, err := keyStore.Eth().Create(&cltest.FixtureChainID) + _, err := keyStore.Eth().Create(testutils.Context(t), &cltest.FixtureChainID) require.NoError(t, err) ethClient := evmtest.NewEthClientMock(t) @@ -436,7 +436,6 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - config, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres @@ -450,7 +449,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) if !test.enableAddress { - err := keyStore.Eth().Disable(fromAddress, testutils.FixtureChainID) + err := keyStore.Eth().Disable(testutils.Context(t), fromAddress, testutils.FixtureChainID) require.NoError(t, err, "failed to disable test key") } diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 332513b28d4..08766d64c8b 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -236,6 +236,7 @@ func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestAppli // NewApplicationWithConfigAndKey creates a new TestApplication with the given testorm // it will also provide an unlocked account on the keystore func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, flagsAndDeps ...interface{}) *TestApplication { + ctx := testutils.Context(t) app := NewApplicationWithConfig(t, c, flagsAndDeps...) chainID := *ubig.New(&FixtureChainID) @@ -252,9 +253,9 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla } else { id, ks := chainID.ToInt(), app.KeyStore.Eth() for _, k := range app.Keys { - ks.XXXTestingOnlyAdd(k) - require.NoError(t, ks.Add(k.Address, id)) - require.NoError(t, ks.Enable(k.Address, id)) + ks.XXXTestingOnlyAdd(ctx, k) + require.NoError(t, ks.Add(ctx, k.Address, id)) + require.NoError(t, ks.Enable(ctx, k.Address, id)) } } @@ -571,9 +572,9 @@ func (ta *TestApplication) MustSeedNewSession(email string) (id string) { } // ImportKey adds private key to the application keystore and database -func (ta *TestApplication) Import(content string) { +func (ta *TestApplication) Import(ctx context.Context, content string) { require.NoError(ta.t, ta.KeyStore.Unlock(Password)) - _, err := ta.KeyStore.Eth().Import([]byte(content), Password, &FixtureChainID) + _, err := ta.KeyStore.Eth().Import(ctx, []byte(content), Password, &FixtureChainID) require.NoError(ta.t, err) } diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 804dbe2d088..2649cc47c6c 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -258,18 +258,19 @@ type RandomKey struct { } func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { + ctx := testutils.Context(t) if r.chainIDs == nil { r.chainIDs = []ubig.Big{*ubig.New(&FixtureChainID)} } key := MustGenerateRandomKey(t) - keystore.XXXTestingOnlyAdd(key) + keystore.XXXTestingOnlyAdd(ctx, key) for _, cid := range r.chainIDs { - require.NoError(t, keystore.Add(key.Address, cid.ToInt())) - require.NoError(t, keystore.Enable(key.Address, cid.ToInt())) + require.NoError(t, keystore.Add(ctx, key.Address, cid.ToInt())) + require.NoError(t, keystore.Enable(ctx, key.Address, cid.ToInt())) if r.Disabled { - require.NoError(t, keystore.Disable(key.Address, cid.ToInt())) + require.NoError(t, keystore.Disable(ctx, key.Address, cid.ToInt())) } } @@ -277,8 +278,9 @@ func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2 } func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { + ctx := testutils.Context(t) k, address := r.MustInsert(t, keystore) - state, err := keystore.GetStateForKey(k) + state, err := keystore.GetStateForKey(ctx, k) require.NoError(t, err) return state, address } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 1c4d097d633..d94452f2512 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -361,6 +361,7 @@ func TestIntegration_DirectRequest(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { + ctx := testutils.Context(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) { @@ -371,7 +372,7 @@ func TestIntegration_DirectRequest(t *testing.T) { b := operatorContracts.sim app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(ctx, testutils.SimulatedChainID) require.NoError(t, err) authorizedSenders := []common.Address{sendingKeys[0].Address} tx, err := operatorContracts.operator.SetAuthorizedSenders(operatorContracts.user, authorizedSenders) @@ -474,7 +475,7 @@ func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *c app = cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, b, lggr) b.Commit() - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) require.Len(t, sendingKeys, 1) @@ -703,7 +704,7 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV2 int, app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) transmitter := sendingKeys[0].Address @@ -745,7 +746,7 @@ func setupForwarderEnabledNode(t *testing.T, owner *bind.TransactOpts, portV2 in app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) transmitter := sendingKeys[0].Address @@ -1360,7 +1361,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { func triggerAllKeys(t *testing.T, app *cltest.TestApplication) { for _, chain := range app.GetRelayers().LegacyEVMChains().Slice() { - keys, err := app.KeyStore.Eth().EnabledKeysForChain(chain.ID()) + keys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), chain.ID()) require.NoError(t, err) for _, k := range keys { chain.TxManager().Trigger(k.Address) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 938b7aa2a66..e089970951b 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -135,7 +135,7 @@ func setupNodeOCR2( app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) require.Len(t, sendingKeys, 1) transmitter := sendingKeys[0].Address diff --git a/core/scripts/chaincli/handler/keeper_upkeep_history.go b/core/scripts/chaincli/handler/keeper_upkeep_history.go index d4237b708f2..487d06dd5ed 100644 --- a/core/scripts/chaincli/handler/keeper_upkeep_history.go +++ b/core/scripts/chaincli/handler/keeper_upkeep_history.go @@ -127,7 +127,7 @@ func (k *Keeper) UpkeepHistory(ctx context.Context, upkeepId *big.Int, from, to, panic("unsupported registry version") } - turnBinary, err2 := turnBlockHashBinary(block, bcpt, defaultLookBackRange, k.client) + turnBinary, err2 := turnBlockHashBinary(ctx, block, bcpt, defaultLookBackRange, k.client) if err2 != nil { log.Fatal("failed to calculate turn block hash: ", err2) } @@ -265,9 +265,9 @@ func printResultsToConsole(parsedResults []result) { fmt.Fprintf(writer, "\n %s\t\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", "----", "----", "----", "----", "----", "----", "----", "----", "----", "----") } -func turnBlockHashBinary(blockNum, bcpt, lookback uint64, ethClient *ethclient.Client) (string, error) { +func turnBlockHashBinary(ctx context.Context, blockNum, bcpt, lookback uint64, ethClient *ethclient.Client) (string, error) { turnBlock := blockNum - (blockNum % bcpt) - lookback - block, err := ethClient.BlockByNumber(context.Background(), big.NewInt(int64(turnBlock))) + block, err := ethClient.BlockByNumber(ctx, big.NewInt(int64(turnBlock))) if err != nil { return "", err } diff --git a/core/services/blockhashstore/bhs.go b/core/services/blockhashstore/bhs.go index 3de00f64590..0ca91c682e7 100644 --- a/core/services/blockhashstore/bhs.go +++ b/core/services/blockhashstore/bhs.go @@ -91,7 +91,7 @@ func (c *BulletproofBHS) Store(ctx context.Context, blockNum uint64) error { return errors.Wrap(err, "packing args") } - fromAddress, err := c.gethks.GetRoundRobinAddress(c.chainID, SendingKeys(c.fromAddresses)...) + fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, SendingKeys(c.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting next from address") } @@ -132,7 +132,7 @@ func (c *BulletproofBHS) StoreTrusted( } // Create a transaction from the given batch and send it to the TXM. - fromAddress, err := c.gethks.GetRoundRobinAddress(c.chainID, SendingKeys(c.fromAddresses)...) + fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, SendingKeys(c.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting next from address") } @@ -186,7 +186,7 @@ func (c *BulletproofBHS) StoreEarliest(ctx context.Context) error { return errors.Wrap(err, "packing args") } - fromAddress, err := c.gethks.GetRoundRobinAddress(c.chainID, c.sendingKeys()...) + fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, c.sendingKeys()...) if err != nil { return errors.Wrap(err, "getting next from address") } diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 44205ec7b86..f8d33b51a34 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -24,6 +24,7 @@ import ( ) func TestStoreRotatesFromAddresses(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewTestGeneralConfig(t) @@ -36,9 +37,9 @@ func TestStoreRotatesFromAddresses(t *testing.T) { lggr := logger.TestLogger(t) ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) require.NoError(t, ks.Unlock("blah")) - k1, err := ks.Eth().Create(&cltest.FixtureChainID) + k1, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - k2, err := ks.Eth().Create(&cltest.FixtureChainID) + k2, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) fromAddresses := []ethkey.EIP55Address{k1.EIP55Address, k2.EIP55Address} txm := new(txmmocks.MockEvmTxManager) @@ -66,8 +67,6 @@ func TestStoreRotatesFromAddresses(t *testing.T) { return tx.FromAddress.String() == k2.Address.String() })).Once().Return(txmgr.Tx{}, nil) - ctx := testutils.Context(t) - // store 2 blocks err = bhs.Store(ctx, 1) require.NoError(t, err) diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index d6c27acd0b5..d07efcb95fe 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -51,7 +51,7 @@ func (d *Delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { if jb.BlockhashStoreSpec == nil { return nil, errors.Errorf( "blockhashstore.Delegate expects a BlockhashStoreSpec to be present, got %+v", jb) @@ -67,7 +67,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { return nil, errors.New("log poller must be enabled to run blockhashstore") } - keys, err := d.ks.EnabledKeysForChain(chain.ID()) + keys, err := d.ks.EnabledKeysForChain(ctx, chain.ID()) if err != nil { return nil, errors.Wrap(err, "getting sending keys") } diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 6fffcfdd493..5f5118afeaf 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -91,7 +91,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { t.Run("happy", func(t *testing.T) { spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*big.Big)(testutils.FixtureChainID)}} - services, err := delegate.ServicesForSpec(spec) + services, err := delegate.ServicesForSpec(testutils.Context(t), spec) require.NoError(t, err) require.Len(t, services, 1) @@ -109,7 +109,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { CoordinatorV2PlusAddress: &coordinatorV2Plus, EVMChainID: (*big.Big)(testutils.FixtureChainID), }} - services, err := delegate.ServicesForSpec(spec) + services, err := delegate.ServicesForSpec(testutils.Context(t), spec) require.NoError(t, err) require.Len(t, services, 1) @@ -117,7 +117,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { t.Run("missing BlockhashStoreSpec", func(t *testing.T) { spec := job.Job{BlockhashStoreSpec: nil} - _, err := delegate.ServicesForSpec(spec) + _, err := delegate.ServicesForSpec(testutils.Context(t), spec) assert.Error(t, err) }) @@ -125,18 +125,19 @@ func TestDelegate_ServicesForSpec(t *testing.T) { spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{ EVMChainID: big.NewI(123), }} - _, err := delegate.ServicesForSpec(spec) + _, err := delegate.ServicesForSpec(testutils.Context(t), spec) assert.Error(t, err) }) t.Run("missing EnabledKeysForChain", func(t *testing.T) { - _, err := testData.ethKeyStore.Delete(testData.sendingKey.ID()) + ctx := testutils.Context(t) + _, err := testData.ethKeyStore.Delete(ctx, testData.sendingKey.ID()) require.NoError(t, err) spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{ WaitBlocks: defaultWaitBlocks, }} - _, err = delegate.ServicesForSpec(spec) + _, err = delegate.ServicesForSpec(testutils.Context(t), spec) assert.Error(t, err) }) } @@ -154,7 +155,7 @@ func TestDelegate_StartStop(t *testing.T) { RunTimeout: testutils.WaitTimeout(t), EVMChainID: (*big.Big)(testutils.FixtureChainID), }} - services, err := delegate.ServicesForSpec(spec) + services, err := delegate.ServicesForSpec(testutils.Context(t), spec) require.NoError(t, err) require.Len(t, services, 1) diff --git a/core/services/blockheaderfeeder/block_header_feeder.go b/core/services/blockheaderfeeder/block_header_feeder.go index a5bcb003613..d1bcab4297a 100644 --- a/core/services/blockheaderfeeder/block_header_feeder.go +++ b/core/services/blockheaderfeeder/block_header_feeder.go @@ -148,7 +148,7 @@ func (f *BlockHeaderFeeder) Run(ctx context.Context) error { } // use 1 sending key for all batches because ordering matters for StoreVerifyHeader - fromAddress, err := f.gethks.GetRoundRobinAddress(f.chainID, blockhashstore.SendingKeys(f.fromAddresses)...) + fromAddress, err := f.gethks.GetRoundRobinAddress(ctx, f.chainID, blockhashstore.SendingKeys(f.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting round robin address") } diff --git a/core/services/blockheaderfeeder/block_header_feeder_test.go b/core/services/blockheaderfeeder/block_header_feeder_test.go index 6c1ec0946e7..1b855caf9d2 100644 --- a/core/services/blockheaderfeeder/block_header_feeder_test.go +++ b/core/services/blockheaderfeeder/block_header_feeder_test.go @@ -202,7 +202,7 @@ func (test testCase) testFeeder(t *testing.T) { fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" fromAddresses := []ethkey.EIP55Address{ethkey.EIP55Address(fromAddress)} ks := keystoremocks.NewEth(t) - ks.On("GetRoundRobinAddress", testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) + ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) feeder := NewBlockHeaderFeeder( lggr, @@ -246,7 +246,7 @@ func TestFeeder_CachesStoredBlocks(t *testing.T) { fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" fromAddresses := []ethkey.EIP55Address{ethkey.EIP55Address(fromAddress)} ks := keystoremocks.NewEth(t) - ks.On("GetRoundRobinAddress", testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) + ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) feeder := NewBlockHeaderFeeder( logger.TestLogger(t), diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 53f514cee27..d78782f6592 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -49,7 +49,7 @@ func (d *Delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { if jb.BlockHeaderFeederSpec == nil { return nil, errors.Errorf("Delegate expects a BlockHeaderFeederSpec to be present, got %+v", jb) } @@ -70,14 +70,14 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { chain.Config().EVM().FinalityDepth(), jb.BlockHeaderFeederSpec.LookbackBlocks) } - keys, err := d.ks.EnabledKeysForChain(chain.ID()) + keys, err := d.ks.EnabledKeysForChain(ctx, chain.ID()) if err != nil { return nil, errors.Wrap(err, "getting sending keys") } if len(keys) == 0 { return nil, fmt.Errorf("missing sending keys for chain ID: %v", chain.ID()) } - if err = CheckFromAddressesExist(jb, d.ks); err != nil { + if err = CheckFromAddressesExist(ctx, jb, d.ks); err != nil { return nil, err } fromAddresses := jb.BlockHeaderFeederSpec.FromAddresses @@ -269,9 +269,9 @@ func (s *service) runFeeder() { // CheckFromAddressesExist returns an error if and only if one of the addresses // in the BlockHeaderFeeder spec's fromAddresses field does not exist in the keystore. -func CheckFromAddressesExist(jb job.Job, gethks keystore.Eth) (err error) { +func CheckFromAddressesExist(ctx context.Context, jb job.Job, gethks keystore.Eth) (err error) { for _, a := range jb.BlockHeaderFeederSpec.FromAddresses { - _, err2 := gethks.Get(a.Hex()) + _, err2 := gethks.Get(ctx, a.Hex()) err = multierr.Append(err, err2) } return diff --git a/core/services/cron/cron_test.go b/core/services/cron/cron_test.go index b561248eddb..5c968c75824 100644 --- a/core/services/cron/cron_test.go +++ b/core/services/cron/cron_test.go @@ -41,7 +41,7 @@ func TestCronV2Pipeline(t *testing.T) { delegate := cron.NewDelegate(runner, lggr) require.NoError(t, jobORM.CreateJob(jb)) - serviceArray, err := delegate.ServicesForSpec(*jb) + serviceArray, err := delegate.ServicesForSpec(testutils.Context(t), *jb) require.NoError(t, err) assert.Len(t, serviceArray, 1) service := serviceArray[0] diff --git a/core/services/cron/delegate.go b/core/services/cron/delegate.go index c227fd60d00..4a08fec5a40 100644 --- a/core/services/cron/delegate.go +++ b/core/services/cron/delegate.go @@ -1,6 +1,8 @@ package cron import ( + "context" + "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -33,7 +35,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the scheduler to be used for running cron jobs -func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { if spec.CronSpec == nil { return nil, errors.Errorf("services.Delegate expects a *jobSpec.CronSpec to be present, got %v", spec) } diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index cfdf1eed116..083e6f02266 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -69,7 +69,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the log listener service for a direct request job -func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { if jb.DirectRequestSpec == nil { return nil, errors.Errorf("DirectRequest: directrequest.Delegate expects a *job.DirectRequestSpec to be present, got %v", jb) } diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 3b80ba2f915..d8540b4471c 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -54,13 +54,13 @@ func TestDelegate_ServicesForSpec(t *testing.T) { t.Run("Spec without DirectRequestSpec", func(t *testing.T) { spec := job.Job{} - _, err := delegate.ServicesForSpec(spec) + _, err := delegate.ServicesForSpec(testutils.Context(t), spec) assert.Error(t, err, "expects a *job.DirectRequestSpec to be present") }) t.Run("Spec with DirectRequestSpec", func(t *testing.T) { spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*ubig.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} - services, err := delegate.ServicesForSpec(spec) + services, err := delegate.ServicesForSpec(testutils.Context(t), spec) require.NoError(t, err) assert.Len(t, services, 1) }) @@ -100,7 +100,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi specF(jb) } require.NoError(t, jobORM.CreateJob(jb)) - serviceArray, err := delegate.ServicesForSpec(*jb) + serviceArray, err := delegate.ServicesForSpec(testutils.Context(t), *jb) require.NoError(t, err) assert.Len(t, serviceArray, 1) service := serviceArray[0] diff --git a/core/services/fluxmonitorv2/contract_submitter.go b/core/services/fluxmonitorv2/contract_submitter.go index 8f3f40c309d..c5a6e599f5d 100644 --- a/core/services/fluxmonitorv2/contract_submitter.go +++ b/core/services/fluxmonitorv2/contract_submitter.go @@ -52,7 +52,7 @@ func NewFluxAggregatorContractSubmitter( // Submit submits the answer by writing a EthTx for the txmgr to // pick up func (c *FluxAggregatorContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { - fromAddress, err := c.keyStore.GetRoundRobinAddress(c.chainID) + fromAddress, err := c.keyStore.GetRoundRobinAddress(ctx, c.chainID) if err != nil { return err } diff --git a/core/services/fluxmonitorv2/contract_submitter_test.go b/core/services/fluxmonitorv2/contract_submitter_test.go index c3b2ca7e715..4c8ce019bfd 100644 --- a/core/services/fluxmonitorv2/contract_submitter_test.go +++ b/core/services/fluxmonitorv2/contract_submitter_test.go @@ -32,7 +32,7 @@ func TestFluxAggregatorContractSubmitter_Submit(t *testing.T) { payload, err := fluxmonitorv2.FluxAggregatorABI.Pack("submit", roundID, submission) assert.NoError(t, err) - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID).Return(fromAddress, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID).Return(fromAddress, nil) fluxAggregator.On("Address").Return(toAddress) idempotencyKey := uuid.New().String() diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index 99e2b688f5d..5de59432d11 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -1,6 +1,8 @@ package fluxmonitorv2 import ( + "context" + "github.com/pkg/errors" "github.com/jmoiron/sqlx" @@ -60,7 +62,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the flux monitor service for the job spec -func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { if jb.FluxMonitorSpec == nil { return nil, errors.Errorf("Delegate expects a *job.FluxMonitorSpec to be present, got %v", jb) } diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 8fe0fc7c70e..f21e56cbc80 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -466,12 +466,17 @@ func formatTime(at time.Time) string { // SetOracleAddress sets the oracle address which matches the node's keys. // If none match, it uses the first available key func (fm *FluxMonitor) SetOracleAddress() error { + + // fm on deprecation path, using dangling context + ctx, cancel := fm.chStop.NewCtx() + defer cancel() + oracleAddrs, err := fm.fluxAggregator.GetOracles(nil) if err != nil { fm.logger.Error("failed to get list of oracles from FluxAggregator contract") return errors.Wrap(err, "failed to get list of oracles from FluxAggregator contract") } - keys, err := fm.keyStore.EnabledKeysForChain(fm.chainID) + keys, err := fm.keyStore.EnabledKeysForChain(ctx, fm.chainID) if err != nil { return errors.Wrap(err, "failed to load keys") } diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index b13edcc12d8..e4db716bbbb 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -358,7 +358,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { fm, tm := setup(t, db) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(tc.connected).Once() // Setup Answers @@ -508,7 +508,7 @@ func TestFluxMonitor_PollIfEligible_Creates_JobErr(t *testing.T) { fm, tm := setup(t, db) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Once() tm.jobORM. @@ -559,7 +559,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { readyToFillQueue := cltest.NewAwaiter() logsAwaiter := cltest.NewAwaiter() - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.fluxAggregator.On("Address").Return(common.Address{}) tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Maybe() @@ -754,7 +754,7 @@ func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(tc.idleTimerDisabled), setIdleTimerPeriod(tc.idleDuration), withORM(orm)) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -833,7 +833,7 @@ func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { setHibernationState(t, true), ) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -926,7 +926,7 @@ func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { setFlags(flags), ) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -1034,7 +1034,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { setIdleTimerPeriod(2*time.Second), ) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -1139,7 +1139,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) tm.keyStore. - On("EnabledKeysForChain", testutils.FixtureChainID). + On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID). Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil). Twice() // Once called from the test, once during start @@ -1200,7 +1200,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) tm.logBroadcaster.On("IsConnected").Return(true).Maybe() @@ -1273,7 +1273,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { ) initialPollOccurred := make(chan struct{}, 1) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) tm.logBroadcaster.On("IsConnected").Return(true).Maybe() tm.fluxAggregator.On("Address").Return(common.Address{}) @@ -1331,7 +1331,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) @@ -1466,7 +1466,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { run := &pipeline.Run{ID: 1} - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() // Mocks initiated by the New Round log @@ -1581,7 +1581,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { ) run := &pipeline.Run{ID: 1} - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() // First, force the node to try to poll, which should result in a submission @@ -1677,7 +1677,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { answer = 100 ) run := &pipeline.Run{ID: 1} - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() tm.logBroadcaster.On("IsConnected").Return(true).Maybe() // First, force the node to try to poll, which should result in a submission @@ -1823,7 +1823,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), enableDrumbeatTicker("@every 3s", 2*time.Second)) - tm.keyStore.On("EnabledKeysForChain", testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil) + tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil) const fetchedAnswer = 100 answerBigInt := big.NewInt(fetchedAnswer) diff --git a/core/services/fluxmonitorv2/key_store.go b/core/services/fluxmonitorv2/key_store.go index 185b59311cb..070d392a922 100644 --- a/core/services/fluxmonitorv2/key_store.go +++ b/core/services/fluxmonitorv2/key_store.go @@ -1,6 +1,7 @@ package fluxmonitorv2 import ( + "context" "math/big" "github.com/ethereum/go-ethereum/common" @@ -13,8 +14,8 @@ import ( // KeyStoreInterface defines an interface to interact with the keystore type KeyStoreInterface interface { - EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) - GetRoundRobinAddress(chainID *big.Int, addrs ...common.Address) (common.Address, error) + EnabledKeysForChain(ctx context.Context, chainID *big.Int) ([]ethkey.KeyV2, error) + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addrs ...common.Address) (common.Address, error) } // KeyStore implements KeyStoreInterface diff --git a/core/services/fluxmonitorv2/key_store_test.go b/core/services/fluxmonitorv2/key_store_test.go index ed0485d3b3c..fdef2ade210 100644 --- a/core/services/fluxmonitorv2/key_store_test.go +++ b/core/services/fluxmonitorv2/key_store_test.go @@ -13,6 +13,7 @@ import ( func TestKeyStore_EnabledKeysForChain(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) @@ -20,17 +21,17 @@ func TestKeyStore_EnabledKeysForChain(t *testing.T) { ks := fluxmonitorv2.NewKeyStore(ethKeyStore) - key, err := ethKeyStore.Create(testutils.FixtureChainID) + key, err := ethKeyStore.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) - key2, err := ethKeyStore.Create(testutils.SimulatedChainID) + key2, err := ethKeyStore.Create(ctx, testutils.SimulatedChainID) require.NoError(t, err) - keys, err := ks.EnabledKeysForChain(testutils.FixtureChainID) + keys, err := ks.EnabledKeysForChain(ctx, testutils.FixtureChainID) require.NoError(t, err) require.Len(t, keys, 1) require.Equal(t, key, keys[0]) - keys, err = ks.EnabledKeysForChain(testutils.SimulatedChainID) + keys, err = ks.EnabledKeysForChain(ctx, testutils.SimulatedChainID) require.NoError(t, err) require.Len(t, keys, 1) require.Equal(t, key2, keys[0]) @@ -39,6 +40,8 @@ func TestKeyStore_EnabledKeysForChain(t *testing.T) { func TestKeyStore_GetRoundRobinAddress(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() @@ -48,7 +51,7 @@ func TestKeyStore_GetRoundRobinAddress(t *testing.T) { ks := fluxmonitorv2.NewKeyStore(ethKeyStore) // Gets the only address in the keystore - addr, err := ks.GetRoundRobinAddress(testutils.FixtureChainID) + addr, err := ks.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) require.Equal(t, k0Address, addr) } diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index 98f5ab71020..7b2aac75e2f 100644 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ b/core/services/fluxmonitorv2/mocks/key_store_interface.go @@ -3,9 +3,11 @@ package mocks import ( + context "context" big "math/big" common "github.com/ethereum/go-ethereum/common" + ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mock "github.com/stretchr/testify/mock" @@ -16,9 +18,9 @@ type KeyStoreInterface struct { mock.Mock } -// EnabledKeysForChain provides a mock function with given fields: chainID -func (_m *KeyStoreInterface) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { - ret := _m.Called(chainID) +// EnabledKeysForChain provides a mock function with given fields: ctx, chainID +func (_m *KeyStoreInterface) EnabledKeysForChain(ctx context.Context, chainID *big.Int) ([]ethkey.KeyV2, error) { + ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for EnabledKeysForChain") @@ -26,19 +28,19 @@ func (_m *KeyStoreInterface) EnabledKeysForChain(chainID *big.Int) ([]ethkey.Key var r0 []ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]ethkey.KeyV2, error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []ethkey.KeyV2); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []ethkey.KeyV2); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.KeyV2) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -46,14 +48,14 @@ func (_m *KeyStoreInterface) EnabledKeysForChain(chainID *big.Int) ([]ethkey.Key return r0, r1 } -// GetRoundRobinAddress provides a mock function with given fields: chainID, addrs -func (_m *KeyStoreInterface) GetRoundRobinAddress(chainID *big.Int, addrs ...common.Address) (common.Address, error) { +// GetRoundRobinAddress provides a mock function with given fields: ctx, chainID, addrs +func (_m *KeyStoreInterface) GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addrs ...common.Address) (common.Address, error) { _va := make([]interface{}, len(addrs)) for _i := range addrs { _va[_i] = addrs[_i] } var _ca []interface{} - _ca = append(_ca, chainID) + _ca = append(_ca, ctx, chainID) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -63,19 +65,19 @@ func (_m *KeyStoreInterface) GetRoundRobinAddress(chainID *big.Int, addrs ...com var r0 common.Address var r1 error - if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { - return rf(chainID, addrs...) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) (common.Address, error)); ok { + return rf(ctx, chainID, addrs...) } - if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) common.Address); ok { - r0 = rf(chainID, addrs...) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) common.Address); ok { + r0 = rf(ctx, chainID, addrs...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.Address) } } - if rf, ok := ret.Get(1).(func(*big.Int, ...common.Address) error); ok { - r1 = rf(chainID, addrs...) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int, ...common.Address) error); ok { + r1 = rf(ctx, chainID, addrs...) } else { r1 = ret.Error(1) } diff --git a/core/services/gateway/delegate.go b/core/services/gateway/delegate.go index 8a97f68d1ea..3100877e96a 100644 --- a/core/services/gateway/delegate.go +++ b/core/services/gateway/delegate.go @@ -1,6 +1,7 @@ package gateway import ( + "context" "encoding/json" "github.com/google/uuid" @@ -46,7 +47,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the scheduler to be used for running observer jobs -func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { if spec.GatewaySpec == nil { return nil, errors.Errorf("services.Delegate expects a *jobSpec.GatewaySpec to be present, got %v", spec) } diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 3590b526022..9716231868c 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -900,57 +900,62 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { } t.Run("test ETH key validation", func(t *testing.T) { + ctx := testutils.Context(t) jb.OCR2OracleSpec.Relay = relay.EVM - err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no EVM key matching: \"bad key\"") _, evmKey := cltest.MustInsertRandomKey(t, keyStore.Eth()) - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, evmKey.String()) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, evmKey.String()) require.NoError(t, err) }) t.Run("test Cosmos key validation", func(t *testing.T) { + ctx := testutils.Context(t) jb.OCR2OracleSpec.Relay = relay.Cosmos - err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Cosmos key matching: \"bad key\"") cosmosKey, err := keyStore.Cosmos().Create() require.NoError(t, err) - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, cosmosKey.ID()) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, cosmosKey.ID()) require.NoError(t, err) }) t.Run("test Solana key validation", func(t *testing.T) { + ctx := testutils.Context(t) jb.OCR2OracleSpec.Relay = relay.Solana - err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Solana key matching: \"bad key\"") solanaKey, err := keyStore.Solana().Create() require.NoError(t, err) - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, solanaKey.ID()) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, solanaKey.ID()) require.NoError(t, err) }) t.Run("test Starknet key validation", func(t *testing.T) { + ctx := testutils.Context(t) jb.OCR2OracleSpec.Relay = relay.StarkNet - err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Starknet key matching: \"bad key\"") starkNetKey, err := keyStore.StarkNet().Create() require.NoError(t, err) - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, starkNetKey.ID()) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, starkNetKey.ID()) require.NoError(t, err) }) t.Run("test Mercury ETH key validation", func(t *testing.T) { + ctx := testutils.Context(t) jb.OCR2OracleSpec.PluginType = types.Mercury - err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no CSA key matching: \"bad key\"") csaKey, err := keyStore.CSA().Create() require.NoError(t, err) - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, csaKey.ID()) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, csaKey.ID()) require.NoError(t, err) }) } diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 2e7bb0a90a5..c608e2cc544 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -192,7 +192,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } } if jb.OCROracleSpec.TransmitterAddress != nil { - _, err := o.keyStore.Eth().Get(jb.OCROracleSpec.TransmitterAddress.Hex()) + _, err := o.keyStore.Eth().Get(q.ParentCtx, jb.OCROracleSpec.TransmitterAddress.Hex()) if err != nil { return errors.Wrapf(ErrNoSuchTransmitterKey, "no key matching transmitter address: %s", jb.OCROracleSpec.TransmitterAddress.Hex()) } @@ -239,7 +239,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } // checks if they are present and if they are valid - sendingKeysDefined, err := areSendingKeysDefined(jb, o.keyStore) + sendingKeysDefined, err := areSendingKeysDefined(q.ParentCtx, jb, o.keyStore) if err != nil { return err } @@ -249,7 +249,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } if !sendingKeysDefined { - if err = ValidateKeyStoreMatch(jb.OCR2OracleSpec, o.keyStore, jb.OCR2OracleSpec.TransmitterID.String); err != nil { + if err = ValidateKeyStoreMatch(q.ParentCtx, jb.OCR2OracleSpec, o.keyStore, jb.OCR2OracleSpec.TransmitterID.String); err != nil { return errors.Wrap(ErrNoSuchTransmitterKey, err.Error()) } } @@ -467,7 +467,7 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { } // ValidateKeyStoreMatch confirms that the key has a valid match in the keystore -func ValidateKeyStoreMatch(spec *OCR2OracleSpec, keyStore keystore.Master, key string) (err error) { +func ValidateKeyStoreMatch(ctx context.Context, spec *OCR2OracleSpec, keyStore keystore.Master, key string) (err error) { switch spec.PluginType { case types.Mercury, types.LLO: _, err = keyStore.CSA().Get(key) @@ -475,15 +475,15 @@ func ValidateKeyStoreMatch(spec *OCR2OracleSpec, keyStore keystore.Master, key s err = errors.Errorf("no CSA key matching: %q", key) } default: - err = validateKeyStoreMatchForRelay(spec.Relay, keyStore, key) + err = validateKeyStoreMatchForRelay(ctx, spec.Relay, keyStore, key) } return } -func validateKeyStoreMatchForRelay(network relay.Network, keyStore keystore.Master, key string) error { +func validateKeyStoreMatchForRelay(ctx context.Context, network relay.Network, keyStore keystore.Master, key string) error { switch network { case relay.EVM: - _, err := keyStore.Eth().Get(key) + _, err := keyStore.Eth().Get(ctx, key) if err != nil { return errors.Errorf("no EVM key matching: %q", key) } @@ -506,7 +506,7 @@ func validateKeyStoreMatchForRelay(network relay.Network, keyStore keystore.Mast return nil } -func areSendingKeysDefined(jb *Job, keystore keystore.Master) (bool, error) { +func areSendingKeysDefined(ctx context.Context, jb *Job, keystore keystore.Master) (bool, error) { if jb.OCR2OracleSpec.RelayConfig["sendingKeys"] != nil { sendingKeys, err := SendingKeysForJob(jb) if err != nil { @@ -514,7 +514,7 @@ func areSendingKeysDefined(jb *Job, keystore keystore.Master) (bool, error) { } for _, sendingKey := range sendingKeys { - if err = ValidateKeyStoreMatch(jb.OCR2OracleSpec, keystore, sendingKey); err != nil { + if err = ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keystore, sendingKey); err != nil { return false, errors.Wrap(ErrNoSuchSendingKey, err.Error()) } } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index fb671982ec5..2722e190e24 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -465,7 +465,7 @@ answer1 [type=median index=0]; config.Database(), servicetest.Run(t, mailboxtest.NewMonitor(t)), ) - _, err = sd.ServicesForSpec(jb) + _, err = sd.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) }) @@ -499,7 +499,7 @@ answer1 [type=median index=0]; config.Database(), servicetest.Run(t, mailboxtest.NewMonitor(t)), ) - _, err = sd.ServicesForSpec(jb) + _, err = sd.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) }) @@ -527,7 +527,7 @@ answer1 [type=median index=0]; config.Database(), servicetest.Run(t, mailboxtest.NewMonitor(t)), ) - _, err = sd.ServicesForSpec(jb) + _, err = sd.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) }) @@ -584,7 +584,7 @@ answer1 [type=median index=0]; ) jb.OCROracleSpec.CaptureEATelemetry = tc.jbCaptureEATelemetry - services, err := sd.ServicesForSpec(jb) + services, err := sd.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) enhancedTelemetryServiceCreated := false @@ -626,7 +626,7 @@ answer1 [type=median index=0]; config.Database(), servicetest.Run(t, mailboxtest.NewMonitor(t)), ) - services, err := sd.ServicesForSpec(*jb) + services, err := sd.ServicesForSpec(testutils.Context(t), *jb) require.NoError(t, err) // Return an error getting the contract code. diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index a16466fbef1..f0486df1c25 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -70,7 +70,7 @@ type ( // job. In case a given job type relies upon well-defined startup/shutdown // ordering for services, they are started in the order they are given // and stopped in reverse order. - ServicesForSpec(Job) ([]ServiceCtx, error) + ServicesForSpec(context.Context, Job) ([]ServiceCtx, error) AfterJobCreated(Job) BeforeJobDeleted(Job) // OnDeleteJob will be called from within DELETE db transaction. Any db @@ -215,7 +215,7 @@ func (js *spawner) StartService(ctx context.Context, jb Job, qopts ...pg.QOpt) e jb.PipelineSpec.GasLimit = &jb.GasLimit.Uint32 } - srvs, err := delegate.ServicesForSpec(jb) + srvs, err := delegate.ServicesForSpec(ctx, jb) if err != nil { lggr.Errorw("Error creating services for job", "err", err) cctx, cancel := js.chStop.NewCtx() @@ -391,7 +391,7 @@ func (n *NullDelegate) JobType() Type { } // ServicesForSpec does no-op. -func (n *NullDelegate) ServicesForSpec(spec Job) (s []ServiceCtx, err error) { +func (n *NullDelegate) ServicesForSpec(ctx context.Context, spec Job) (s []ServiceCtx, err error) { return } diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 9dde7a47721..71357a675c3 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -1,6 +1,7 @@ package job_test import ( + "context" "testing" "time" @@ -52,7 +53,7 @@ func (d delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d delegate) ServicesForSpec(js job.Job) ([]job.ServiceCtx, error) { +func (d delegate) ServicesForSpec(ctx context.Context, js job.Job) ([]job.ServiceCtx, error) { if js.Type != d.jobType { return nil, nil } diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 4418bea670a..c2c546fcd33 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -1,6 +1,8 @@ package keeper import ( + "context" + "github.com/pkg/errors" "github.com/jmoiron/sqlx" @@ -55,7 +57,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) { if spec.KeeperSpec == nil { return nil, errors.Errorf("Delegate expects a *job.KeeperSpec to be present, got %v", spec) } diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 590c9720cb2..1018d5f2aab 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -226,14 +226,15 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { }) t.Run("errors if submission key not found", func(t *testing.T) { + ctx := testutils.Context(t) _, _, ethMock, executer, registry, _, job, jpv2, _, keyStore, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) // replace expected key with random one - _, err := keyStore.Eth().Create(testutils.SimulatedChainID) + _, err := keyStore.Eth().Create(ctx, testutils.SimulatedChainID) require.NoError(t, err) - _, err = keyStore.Eth().Delete(job.KeeperSpec.FromAddress.Hex()) + _, err = keyStore.Eth().Delete(ctx, job.KeeperSpec.FromAddress.Hex()) require.NoError(t, err) registryMock := cltest.NewContractMockReceiver(t, ethMock, keeper.Registry1_1ABI, registry.ContractAddress.Address()) diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index 0e86cccacae..be59cb5e54c 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -1,6 +1,7 @@ package keystore import ( + "context" "fmt" "math/big" "sort" @@ -21,34 +22,34 @@ import ( // //go:generate mockery --quiet --name Eth --output mocks/ --case=underscore type Eth interface { - Get(id string) (ethkey.KeyV2, error) - GetAll() ([]ethkey.KeyV2, error) - Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) - Delete(id string) (ethkey.KeyV2, error) - Import(keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) - Export(id string, password string) ([]byte, error) + Get(ctx context.Context, id string) (ethkey.KeyV2, error) + GetAll(ctx context.Context) ([]ethkey.KeyV2, error) + Create(ctx context.Context, chainIDs ...*big.Int) (ethkey.KeyV2, error) + Delete(ctx context.Context, id string) (ethkey.KeyV2, error) + Import(ctx context.Context, keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) + Export(ctx context.Context, id string, password string) ([]byte, error) - Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error + Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error + Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error + Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - EnsureKeys(chainIDs ...*big.Int) error - SubscribeToKeyChanges() (ch chan struct{}, unsub func()) + EnsureKeys(ctx context.Context, chainIDs ...*big.Int) error + SubscribeToKeyChanges(ctx context.Context) (ch chan struct{}, unsub func()) - SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) + SignTx(ctx context.Context, fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) - EnabledKeysForChain(chainID *big.Int) (keys []ethkey.KeyV2, err error) - GetRoundRobinAddress(chainID *big.Int, addresses ...common.Address) (address common.Address, err error) - CheckEnabled(address common.Address, chainID *big.Int) error + EnabledKeysForChain(ctx context.Context, chainID *big.Int) (keys []ethkey.KeyV2, err error) + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (address common.Address, err error) + CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error - GetState(id string, chainID *big.Int) (ethkey.State, error) - GetStatesForKeys([]ethkey.KeyV2) ([]ethkey.State, error) - GetStateForKey(ethkey.KeyV2) (ethkey.State, error) - GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) - EnabledAddressesForChain(chainID *big.Int) (addresses []common.Address, err error) + GetState(ctx context.Context, id string, chainID *big.Int) (ethkey.State, error) + GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) ([]ethkey.State, error) + GetStateForKey(ctx context.Context, key ethkey.KeyV2) (ethkey.State, error) + GetStatesForChain(ctx context.Context, chainID *big.Int) ([]ethkey.State, error) + EnabledAddressesForChain(ctx context.Context, chainID *big.Int) (addresses []common.Address, err error) - XXXTestingOnlySetState(ethkey.State) - XXXTestingOnlyAdd(key ethkey.KeyV2) + XXXTestingOnlySetState(ctx context.Context, keyState ethkey.State) + XXXTestingOnlyAdd(ctx context.Context, key ethkey.KeyV2) } type eth struct { @@ -71,7 +72,7 @@ func newEthKeyStore(km *keyManager, orm keystateORM, q pg.Q) *eth { } } -func (ks *eth) Get(id string) (ethkey.KeyV2, error) { +func (ks *eth) Get(ctx context.Context, id string) (ethkey.KeyV2, error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { @@ -80,17 +81,17 @@ func (ks *eth) Get(id string) (ethkey.KeyV2, error) { return ks.getByID(id) } -func (ks *eth) GetAll() (keys []ethkey.KeyV2, _ error) { +func (ks *eth) GetAll(ctx context.Context) (keys []ethkey.KeyV2, _ error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { return nil, ErrLocked } - return ks.getAll(), nil + return ks.getAll(ctx), nil } // caller must hold lock! -func (ks *eth) getAll() (keys []ethkey.KeyV2) { +func (ks *eth) getAll(ctx context.Context) (keys []ethkey.KeyV2) { for _, key := range ks.keyRing.Eth { keys = append(keys, key) } @@ -99,7 +100,7 @@ func (ks *eth) getAll() (keys []ethkey.KeyV2) { } // Create generates a fresh new key and enables it for the given chain IDs -func (ks *eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { +func (ks *eth) Create(ctx context.Context, chainIDs ...*big.Int) (ethkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -109,7 +110,7 @@ func (ks *eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { if err != nil { return ethkey.KeyV2{}, err } - err = ks.add(key, chainIDs...) + err = ks.add(ctx, key, chainIDs...) if err == nil { ks.notify() } @@ -120,7 +121,7 @@ func (ks *eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { // EnsureKeys ensures that each chain has at least one key with a state // linked to that chain. If a key and state exists for a chain but it is // disabled, we do not enable it automatically here. -func (ks *eth) EnsureKeys(chainIDs ...*big.Int) (err error) { +func (ks *eth) EnsureKeys(ctx context.Context, chainIDs ...*big.Int) (err error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -136,7 +137,7 @@ func (ks *eth) EnsureKeys(chainIDs ...*big.Int) (err error) { if err != nil { return err } - err = ks.add(newKey, chainID) + err = ks.add(ctx, newKey, chainID) if err != nil { return err } @@ -146,7 +147,7 @@ func (ks *eth) EnsureKeys(chainIDs ...*big.Int) (err error) { return nil } -func (ks *eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) { +func (ks *eth) Import(ctx context.Context, keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -160,7 +161,7 @@ func (ks *eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et if _, found := ks.keyRing.Eth[key.ID()]; found { return ethkey.KeyV2{}, ErrKeyExists } - err = ks.add(key, chainIDs...) + err = ks.add(ctx, key, chainIDs...) if err != nil { return ethkey.KeyV2{}, errors.Wrap(err, "unable to add eth key") } @@ -168,7 +169,7 @@ func (ks *eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et return key, nil } -func (ks *eth) Export(id string, password string) ([]byte, error) { +func (ks *eth) Export(ctx context.Context, id string, password string) ([]byte, error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { @@ -181,23 +182,25 @@ func (ks *eth) Export(id string, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return ErrKeyNotFound } - return ks.addKey(address, chainID, qopts...) + return ks.addKey(ctx, address, chainID, qopts...) } // caller must hold lock! -func (ks *eth) addKey(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) addKey(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) sql := `INSERT INTO evm.key_states (address, disabled, evm_chain_id, created_at, updated_at) VALUES ($1, false, $2, NOW(), NOW()) RETURNING *;` q := ks.q.WithOpts(qopts...) + q = q.WithOpts(pg.WithParentCtx(ctx)) + if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to insert evm_key_state") } @@ -207,18 +210,18 @@ func (ks *eth) addKey(address common.Address, chainID *big.Int, qopts ...pg.QOpt return nil } -func (ks *eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return ErrKeyNotFound } - return ks.enable(address, chainID, qopts...) + return ks.enable(ctx, address, chainID, qopts...) } // caller must hold lock! -func (ks *eth) enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.q.WithOpts(qopts...) sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, false, NOW(), NOW()) @@ -237,17 +240,17 @@ func (ks *eth) enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt return nil } -func (ks *eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { ks.lock.Lock() defer ks.lock.Unlock() _, found := ks.keyRing.Eth[address.Hex()] if !found { return errors.Errorf("no key exists with ID %s", address.Hex()) } - return ks.disable(address, chainID, qopts...) + return ks.disable(ctx, address, chainID, qopts...) } -func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +func (ks *eth) disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) q := ks.q.WithOpts(qopts...) sql := `INSERT INTO evm.key_states as key_states ("address", "evm_chain_id", "disabled", "created_at", "updated_at") VALUES ($1, $2, true, NOW(), NOW()) @@ -266,7 +269,7 @@ func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOp return nil } -func (ks *eth) Delete(id string) (ethkey.KeyV2, error) { +func (ks *eth) Delete(ctx context.Context, id string) (ethkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -288,7 +291,7 @@ func (ks *eth) Delete(id string) (ethkey.KeyV2, error) { return key, nil } -func (ks *eth) SubscribeToKeyChanges() (ch chan struct{}, unsub func()) { +func (ks *eth) SubscribeToKeyChanges(ctx context.Context) (ch chan struct{}, unsub func()) { ch = make(chan struct{}, 1) ks.subscribersMu.Lock() defer ks.subscribersMu.Unlock() @@ -305,7 +308,7 @@ func (ks *eth) SubscribeToKeyChanges() (ch chan struct{}, unsub func()) { } } -func (ks *eth) SignTx(address common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { +func (ks *eth) SignTx(ctx context.Context, address common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { @@ -320,7 +323,7 @@ func (ks *eth) SignTx(address common.Address, tx *types.Transaction, chainID *bi } // EnabledKeysForChain returns all keys that are enabled for the given chain -func (ks *eth) EnabledKeysForChain(chainID *big.Int) (sendingKeys []ethkey.KeyV2, err error) { +func (ks *eth) EnabledKeysForChain(ctx context.Context, chainID *big.Int) (sendingKeys []ethkey.KeyV2, err error) { if chainID == nil { return nil, errors.New("chainID must be non-nil") } @@ -332,7 +335,7 @@ func (ks *eth) EnabledKeysForChain(chainID *big.Int) (sendingKeys []ethkey.KeyV2 return ks.enabledKeysForChain(chainID), nil } -func (ks *eth) GetRoundRobinAddress(chainID *big.Int, whitelist ...common.Address) (common.Address, error) { +func (ks *eth) GetRoundRobinAddress(ctx context.Context, chainID *big.Int, whitelist ...common.Address) (common.Address, error) { if chainID == nil { return common.Address{}, errors.New("chainID must be non-nil") } @@ -381,7 +384,7 @@ func (ks *eth) GetRoundRobinAddress(chainID *big.Int, whitelist ...common.Addres // CheckEnabled returns nil if state is present and enabled // The complexity here comes because we want to return nice, useful error messages -func (ks *eth) CheckEnabled(address common.Address, chainID *big.Int) error { +func (ks *eth) CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error { if utils.IsZero(address) { return errors.Errorf("empty address provided as input") } @@ -423,7 +426,7 @@ func (ks *eth) CheckEnabled(address common.Address, chainID *big.Int) error { return nil } -func (ks *eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { +func (ks *eth) GetState(ctx context.Context, id string, chainID *big.Int) (ethkey.State, error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { @@ -436,7 +439,7 @@ func (ks *eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { return *state, nil } -func (ks *eth) GetStatesForKeys(keys []ethkey.KeyV2) (states []ethkey.State, err error) { +func (ks *eth) GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) (states []ethkey.State, err error) { ks.lock.RLock() defer ks.lock.RUnlock() for _, state := range ks.keyStates.All { @@ -451,7 +454,7 @@ func (ks *eth) GetStatesForKeys(keys []ethkey.KeyV2) (states []ethkey.State, err } // Useful to fetch the ChainID for a given key -func (ks *eth) GetStateForKey(key ethkey.KeyV2) (state ethkey.State, err error) { +func (ks *eth) GetStateForKey(ctx context.Context, key ethkey.KeyV2) (state ethkey.State, err error) { ks.lock.RLock() defer ks.lock.RUnlock() for _, state := range ks.keyStates.All { @@ -463,7 +466,7 @@ func (ks *eth) GetStateForKey(key ethkey.KeyV2) (state ethkey.State, err error) return } -func (ks *eth) GetStatesForChain(chainID *big.Int) (states []ethkey.State, err error) { +func (ks *eth) GetStatesForChain(ctx context.Context, chainID *big.Int) (states []ethkey.State, err error) { ks.lock.RLock() defer ks.lock.RUnlock() if ks.isLocked() { @@ -476,7 +479,7 @@ func (ks *eth) GetStatesForChain(chainID *big.Int) (states []ethkey.State, err e return } -func (ks *eth) EnabledAddressesForChain(chainID *big.Int) (addresses []common.Address, err error) { +func (ks *eth) EnabledAddressesForChain(ctx context.Context, chainID *big.Int) (addresses []common.Address, err error) { ks.lock.RLock() defer ks.lock.RUnlock() if chainID == nil { @@ -495,7 +498,7 @@ func (ks *eth) EnabledAddressesForChain(chainID *big.Int) (addresses []common.Ad } // XXXTestingOnlySetState is only used in tests to manually update a key's state -func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { +func (ks *eth) XXXTestingOnlySetState(ctx context.Context, state ethkey.State) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -515,7 +518,7 @@ func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { } // XXXTestingOnlyAdd is only used in tests to manually add a key -func (ks *eth) XXXTestingOnlyAdd(key ethkey.KeyV2) { +func (ks *eth) XXXTestingOnlyAdd(ctx context.Context, key ethkey.KeyV2) { ks.lock.Lock() defer ks.lock.Unlock() if ks.isLocked() { @@ -524,7 +527,7 @@ func (ks *eth) XXXTestingOnlyAdd(key ethkey.KeyV2) { if _, found := ks.keyRing.Eth[key.ID()]; found { panic(fmt.Sprintf("key with ID %s already exists", key.ID())) } - err := ks.add(key) + err := ks.add(ctx, key) if err != nil { panic(err.Error()) } @@ -561,10 +564,10 @@ func (ks *eth) keysForChain(chainID *big.Int, includeDisabled bool) (keys []ethk } // caller must hold lock! -func (ks *eth) add(key ethkey.KeyV2, chainIDs ...*big.Int) (err error) { +func (ks *eth) add(ctx context.Context, key ethkey.KeyV2, chainIDs ...*big.Int) (err error) { err = ks.safeAddKey(key, func(tx pg.Queryer) (serr error) { for _, chainID := range chainIDs { - if serr = ks.addKey(key.Address, chainID, pg.WithQueryer(tx)); serr != nil { + if serr = ks.addKey(ctx, key.Address, chainID, pg.WithQueryer(tx)); serr != nil { return serr } } diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index dd42f4049c3..573830638ab 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -43,14 +43,15 @@ func Test_EthKeyStore(t *testing.T) { const statesTableName = "evm.key_states" t.Run("Create / GetAll / Get", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ethKeyStore.Create(&cltest.FixtureChainID) + key, err := ethKeyStore.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - retrievedKeys, err := ethKeyStore.GetAll() + retrievedKeys, err := ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 1, len(retrievedKeys)) require.Equal(t, key.Address, retrievedKeys[0].Address) - foundKey, err := ethKeyStore.Get(key.Address.Hex()) + foundKey, err := ethKeyStore.Get(ctx, key.Address.Hex()) require.NoError(t, err) require.Equal(t, key, foundKey) // adds ethkey.State @@ -62,27 +63,28 @@ func Test_EthKeyStore(t *testing.T) { // adds key to db keyStore.ResetXXXTestOnly() require.NoError(t, keyStore.Unlock(cltest.Password)) - retrievedKeys, err = ethKeyStore.GetAll() + retrievedKeys, err = ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 1, len(retrievedKeys)) require.Equal(t, key.Address, retrievedKeys[0].Address) // adds 2nd key - _, err = ethKeyStore.Create(&cltest.FixtureChainID) + _, err = ethKeyStore.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - retrievedKeys, err = ethKeyStore.GetAll() + retrievedKeys, err = ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 2, len(retrievedKeys)) }) t.Run("GetAll ordering", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() var keys []ethkey.KeyV2 for i := 0; i < 5; i++ { - key, err := ethKeyStore.Create(&cltest.FixtureChainID) + key, err := ethKeyStore.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) keys = append(keys, key) } - retrievedKeys, err := ethKeyStore.GetAll() + retrievedKeys, err := ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 5, len(retrievedKeys)) @@ -92,20 +94,22 @@ func Test_EthKeyStore(t *testing.T) { }) t.Run("RemoveKey", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ethKeyStore.Create(&cltest.FixtureChainID) + key, err := ethKeyStore.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - _, err = ethKeyStore.Delete(key.ID()) + _, err = ethKeyStore.Delete(ctx, key.ID()) require.NoError(t, err) - retrievedKeys, err := ethKeyStore.GetAll() + retrievedKeys, err := ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 0, len(retrievedKeys)) cltest.AssertCount(t, db, statesTableName, 0) }) t.Run("Delete removes key even if evm.txes are present", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ethKeyStore.Create(&cltest.FixtureChainID) + key, err := ethKeyStore.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) // ensure at least one state is present cltest.AssertCount(t, db, statesTableName, 1) @@ -114,27 +118,28 @@ func Test_EthKeyStore(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 42, key.Address) - _, err = ethKeyStore.Delete(key.ID()) + _, err = ethKeyStore.Delete(ctx, key.ID()) require.NoError(t, err) - retrievedKeys, err := ethKeyStore.GetAll() + retrievedKeys, err := ethKeyStore.GetAll(ctx) require.NoError(t, err) require.Equal(t, 0, len(retrievedKeys)) cltest.AssertCount(t, db, statesTableName, 0) }) t.Run("EnsureKeys / EnabledKeysForChain", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - err := ethKeyStore.EnsureKeys(&cltest.FixtureChainID) + err := ethKeyStore.EnsureKeys(ctx, &cltest.FixtureChainID) assert.NoError(t, err) - sendingKeys1, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) + sendingKeys1, err := ethKeyStore.EnabledKeysForChain(ctx, testutils.FixtureChainID) assert.NoError(t, err) require.Equal(t, 1, len(sendingKeys1)) cltest.AssertCount(t, db, statesTableName, 1) - err = ethKeyStore.EnsureKeys(&cltest.FixtureChainID) + err = ethKeyStore.EnsureKeys(ctx, &cltest.FixtureChainID) assert.NoError(t, err) - sendingKeys2, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) + sendingKeys2, err := ethKeyStore.EnabledKeysForChain(ctx, testutils.FixtureChainID) assert.NoError(t, err) require.Equal(t, 1, len(sendingKeys2)) @@ -142,63 +147,65 @@ func Test_EthKeyStore(t *testing.T) { }) t.Run("EnabledKeysForChain with specified chain ID", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ethKeyStore.Create(testutils.FixtureChainID) + key, err := ethKeyStore.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) - key2, err := ethKeyStore.Create(big.NewInt(1337)) + key2, err := ethKeyStore.Create(ctx, big.NewInt(1337)) require.NoError(t, err) - keys, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) + keys, err := ethKeyStore.EnabledKeysForChain(ctx, testutils.FixtureChainID) require.NoError(t, err) require.Len(t, keys, 1) require.Equal(t, key, keys[0]) - keys, err = ethKeyStore.EnabledKeysForChain(big.NewInt(1337)) + keys, err = ethKeyStore.EnabledKeysForChain(ctx, big.NewInt(1337)) require.NoError(t, err) require.Len(t, keys, 1) require.Equal(t, key2, keys[0]) - _, err = ethKeyStore.EnabledKeysForChain(nil) + _, err = ethKeyStore.EnabledKeysForChain(ctx, nil) assert.Error(t, err) assert.EqualError(t, err, "chainID must be non-nil") }) t.Run("EnabledAddressesForChain with specified chain ID", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ethKeyStore.Create(testutils.FixtureChainID) + key, err := ethKeyStore.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) - key2, err := ethKeyStore.Create(big.NewInt(1337)) + key2, err := ethKeyStore.Create(ctx, big.NewInt(1337)) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 2) - keys, err := ethKeyStore.GetAll() + keys, err := ethKeyStore.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 2) //get enabled addresses for FixtureChainID - enabledAddresses, err := ethKeyStore.EnabledAddressesForChain(testutils.FixtureChainID) + enabledAddresses, err := ethKeyStore.EnabledAddressesForChain(ctx, testutils.FixtureChainID) require.NoError(t, err) require.Len(t, enabledAddresses, 1) require.Equal(t, key.Address, enabledAddresses[0]) //get enabled addresses for chain 1337 - enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(big.NewInt(1337)) + enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(ctx, big.NewInt(1337)) require.NoError(t, err) require.Len(t, enabledAddresses, 1) require.Equal(t, key2.Address, enabledAddresses[0]) // /get enabled addresses for nil chain ID - _, err = ethKeyStore.EnabledAddressesForChain(nil) + _, err = ethKeyStore.EnabledAddressesForChain(ctx, nil) assert.Error(t, err) assert.EqualError(t, err, "chainID must be non-nil") // disable the key for chain FixtureChainID - err = ethKeyStore.Disable(key.Address, testutils.FixtureChainID) + err = ethKeyStore.Disable(ctx, key.Address, testutils.FixtureChainID) require.NoError(t, err) - enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(testutils.FixtureChainID) + enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(ctx, testutils.FixtureChainID) require.NoError(t, err) assert.Len(t, enabledAddresses, 0) - enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(big.NewInt(1337)) + enabledAddresses, err = ethKeyStore.EnabledAddressesForChain(ctx, big.NewInt(1337)) require.NoError(t, err) assert.Len(t, enabledAddresses, 1) require.Equal(t, key2.Address, enabledAddresses[0]) @@ -206,6 +213,7 @@ func Test_EthKeyStore(t *testing.T) { } func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { + ctx := testutils.Context(t) t.Parallel() db := pgtest.NewSqlxDB(t) @@ -215,7 +223,8 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { ethKeyStore := keyStore.Eth() t.Run("should error when no addresses", func(t *testing.T) { - _, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + ctx1 := testutils.Context(t) + _, err := ethKeyStore.GetRoundRobinAddress(ctx1, testutils.FixtureChainID) require.Error(t, err) }) @@ -231,38 +240,38 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { // - key 4 // enabled - fixture k1, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) - require.NoError(t, ethKeyStore.Add(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ethKeyStore.Add(k1.Address, testutils.SimulatedChainID)) - require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k1.Address, testutils.SimulatedChainID)) k2, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) - require.NoError(t, ethKeyStore.Add(k2.Address, testutils.FixtureChainID)) - require.NoError(t, ethKeyStore.Add(k2.Address, testutils.SimulatedChainID)) - require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.FixtureChainID)) - require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.SimulatedChainID)) - require.NoError(t, ethKeyStore.Disable(k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k2.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k2.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Disable(ctx, k2.Address, testutils.SimulatedChainID)) k3, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) - require.NoError(t, ethKeyStore.Add(k3.Address, testutils.SimulatedChainID)) - require.NoError(t, ethKeyStore.Enable(k3.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k3.Address, testutils.SimulatedChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k3.Address, testutils.SimulatedChainID)) k4, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) - require.NoError(t, ethKeyStore.Add(k4.Address, testutils.FixtureChainID)) - require.NoError(t, ethKeyStore.Enable(k4.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Add(ctx, k4.Address, testutils.FixtureChainID)) + require.NoError(t, ethKeyStore.Enable(ctx, k4.Address, testutils.FixtureChainID)) t.Run("with no address filter, rotates between all enabled addresses", func(t *testing.T) { - address1, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address1, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) - address2, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address2, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) - address3, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address3, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) - address4, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address4, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) - address5, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address5, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) - address6, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID) + address6, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID) require.NoError(t, err) assert.NotEqual(t, address1, address2) @@ -278,13 +287,13 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { // k3 is a disabled address for FixtureChainID so even though it's whitelisted, it will be ignored addresses := []common.Address{k4.Address, k3.Address, k1.Address, k2.Address, testutils.NewAddress()} - address1, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID, addresses...) + address1, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID, addresses...) require.NoError(t, err) - address2, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID, addresses...) + address2, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID, addresses...) require.NoError(t, err) - address3, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID, addresses...) + address3, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID, addresses...) require.NoError(t, err) - address4, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID, addresses...) + address4, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID, addresses...) require.NoError(t, err) assert.NotEqual(t, k3.Address, address1) @@ -301,13 +310,13 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { // k2 and k4 are disabled address for SimulatedChainID so even though it's whitelisted, it will be ignored addresses := []common.Address{k4.Address, k3.Address, k1.Address, k2.Address, testutils.NewAddress()} - address1, err := ethKeyStore.GetRoundRobinAddress(testutils.SimulatedChainID, addresses...) + address1, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.SimulatedChainID, addresses...) require.NoError(t, err) - address2, err := ethKeyStore.GetRoundRobinAddress(testutils.SimulatedChainID, addresses...) + address2, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.SimulatedChainID, addresses...) require.NoError(t, err) - address3, err := ethKeyStore.GetRoundRobinAddress(testutils.SimulatedChainID, addresses...) + address3, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.SimulatedChainID, addresses...) require.NoError(t, err) - address4, err := ethKeyStore.GetRoundRobinAddress(testutils.SimulatedChainID, addresses...) + address4, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.SimulatedChainID, addresses...) require.NoError(t, err) assert.True(t, address1 == k1.Address || address1 == k3.Address) @@ -320,7 +329,7 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { t.Run("with address filter when no address matches", func(t *testing.T) { addr := testutils.NewAddress() - _, err := ethKeyStore.GetRoundRobinAddress(testutils.FixtureChainID, []common.Address{addr}...) + _, err := ethKeyStore.GetRoundRobinAddress(ctx, testutils.FixtureChainID, []common.Address{addr}...) require.Error(t, err) require.Equal(t, fmt.Sprintf("no sending keys available for chain %s that match whitelist: [%s]", testutils.FixtureChainID.String(), addr.Hex()), err.Error()) }) @@ -329,6 +338,8 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { func Test_EthKeyStore_SignTx(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) config := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) @@ -340,10 +351,10 @@ func Test_EthKeyStore_SignTx(t *testing.T) { 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) + _, err := ethKeyStore.SignTx(ctx, randomAddress, tx, chainID) require.EqualError(t, err, "Key not found") - signed, err := ethKeyStore.SignTx(k.Address, tx, chainID) + signed, err := ethKeyStore.SignTx(ctx, k.Address, tx, chainID) require.NoError(t, err) require.NotEqual(t, tx, signed) @@ -367,78 +378,85 @@ func Test_EthKeyStore_E2E(t *testing.T) { } t.Run("initializes with an empty state", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) require.NoError(t, err) require.Equal(t, 0, len(keys)) }) t.Run("errors when getting non-existent ID", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - _, err := ks.Get("non-existent-id") + _, err := ks.Get(ctx, "non-existent-id") require.Error(t, err) }) t.Run("creates a key", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ks.Create(&cltest.FixtureChainID) + key, err := ks.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - retrievedKey, err := ks.Get(key.ID()) + retrievedKey, err := ks.Get(ctx, key.ID()) require.NoError(t, err) require.Equal(t, key, retrievedKey) }) t.Run("imports and exports a key", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() - key, err := ks.Create(&cltest.FixtureChainID) + key, err := ks.Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - exportJSON, err := ks.Export(key.ID(), cltest.Password) + exportJSON, err := ks.Export(ctx, key.ID(), cltest.Password) require.NoError(t, err) - _, err = ks.Delete(key.ID()) + _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) - _, err = ks.Get(key.ID()) + _, err = ks.Get(ctx, key.ID()) require.Error(t, err) - importedKey, err := ks.Import(exportJSON, cltest.Password, &cltest.FixtureChainID) + importedKey, err := ks.Import(ctx, exportJSON, cltest.Password, &cltest.FixtureChainID) require.NoError(t, err) require.Equal(t, key.ID(), importedKey.ID()) - retrievedKey, err := ks.Get(key.ID()) + retrievedKey, err := ks.Get(ctx, key.ID()) require.NoError(t, err) require.Equal(t, importedKey, retrievedKey) }) t.Run("adds an externally created key / deletes a key", func(t *testing.T) { + ctx := testutils.Context(t) defer reset() newKey, err := ethkey.NewV2() require.NoError(t, err) - ks.XXXTestingOnlyAdd(newKey) - keys, err := ks.GetAll() + ks.XXXTestingOnlyAdd(ctx, newKey) + keys, err := ks.GetAll(ctx) require.NoError(t, err) assert.Equal(t, 1, len(keys)) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) - keys, err = ks.GetAll() + keys, err = ks.GetAll(ctx) require.NoError(t, err) assert.Equal(t, 0, len(keys)) - _, err = ks.Get(newKey.ID()) + _, err = ks.Get(ctx, newKey.ID()) assert.Error(t, err) - _, err = ks.Delete(newKey.ID()) + _, err = ks.Delete(ctx, newKey.ID()) assert.Error(t, err) }) t.Run("imports a key exported from a v1 keystore", func(t *testing.T) { + ctx := testutils.Context(t) exportedKey := `{"address":"0dd359b4f22a30e44b2fd744b679971941865820","crypto":{"cipher":"aes-128-ctr","ciphertext":"b30af964a3b3f37894e599446b4cf2314bbfcd1062e6b35b620d3d20bd9965cc","cipherparams":{"iv":"58a8d75629cc1945da7cf8c24520d1dc"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c352887e9d427d8a6a1869082619b73fac4566082a99f6e367d126f11b434f28"},"mac":"fd76a588210e0bf73d01332091e0e83a4584ee2df31eaec0e27f9a1b94f024b4"},"id":"a5ee0802-1d7b-45b6-aeb8-ea8a3351e715","version":3}` - importedKey, err := ks.Import([]byte(exportedKey), "p4SsW0rD1!@#_", &cltest.FixtureChainID) + importedKey, err := ks.Import(ctx, []byte(exportedKey), "p4SsW0rD1!@#_", &cltest.FixtureChainID) require.NoError(t, err) assert.Equal(t, "0x0dd359b4f22a30E44b2fD744B679971941865820", importedKey.ID()) - k, err := ks.Import([]byte(exportedKey), cltest.Password, &cltest.FixtureChainID) + k, err := ks.Import(ctx, []byte(exportedKey), cltest.Password, &cltest.FixtureChainID) assert.Empty(t, k) assert.Error(t, err) }) t.Run("fails to export a non-existent key", func(t *testing.T) { - k, err := ks.Export("non-existent", cltest.Password) + ctx := testutils.Context(t) + k, err := ks.Export(ctx, "non-existent", cltest.Password) assert.Empty(t, k) assert.Error(t, err) @@ -448,24 +466,25 @@ func Test_EthKeyStore_E2E(t *testing.T) { defer reset() t.Run("returns states for keys", func(t *testing.T) { + ctx := testutils.Context(t) k1, err := ethkey.NewV2() require.NoError(t, err) k2, err := ethkey.NewV2() require.NoError(t, err) - ks.XXXTestingOnlyAdd(k1) - ks.XXXTestingOnlyAdd(k2) - require.NoError(t, ks.Add(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) + ks.XXXTestingOnlyAdd(ctx, k1) + ks.XXXTestingOnlyAdd(ctx, k2) + require.NoError(t, ks.Add(ctx, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx, k1.Address, testutils.FixtureChainID)) - states, err := ks.GetStatesForKeys([]ethkey.KeyV2{k1, k2}) + states, err := ks.GetStatesForKeys(ctx, []ethkey.KeyV2{k1, k2}) require.NoError(t, err) assert.Len(t, states, 1) - chainStates, err := ks.GetStatesForChain(testutils.FixtureChainID) + chainStates, err := ks.GetStatesForChain(ctx, testutils.FixtureChainID) require.NoError(t, err) assert.Len(t, chainStates, 2) // one created here, one created above - chainStates, err = ks.GetStatesForChain(testutils.SimulatedChainID) + chainStates, err = ks.GetStatesForChain(ctx, testutils.SimulatedChainID) require.NoError(t, err) assert.Len(t, chainStates, 0) }) @@ -475,13 +494,15 @@ func Test_EthKeyStore_E2E(t *testing.T) { func Test_EthKeyStore_SubscribeToKeyChanges(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) + chDone := make(chan struct{}) defer func() { close(chDone) }() db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() - chSub, unsubscribe := ks.SubscribeToKeyChanges() + chSub, unsubscribe := ks.SubscribeToKeyChanges(ctx) defer unsubscribe() var count atomic.Int32 @@ -517,28 +538,28 @@ func Test_EthKeyStore_SubscribeToKeyChanges(t *testing.T) { count.Store(0) } - err := ks.EnsureKeys(&cltest.FixtureChainID) + err := ks.EnsureKeys(ctx, &cltest.FixtureChainID) require.NoError(t, err) assertCountAtLeast(1) drainAndReset() // Create the key includes a state, triggering notify - k1, err := ks.Create(testutils.FixtureChainID) + k1, err := ks.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) assertCountAtLeast(1) drainAndReset() // Enabling the key for a new state triggers the notification callback again - require.NoError(t, ks.Add(k1.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, k1.Address, testutils.SimulatedChainID)) assertCountAtLeast(1) drainAndReset() // Disabling triggers a notify - require.NoError(t, ks.Disable(k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Disable(ctx, k1.Address, testutils.SimulatedChainID)) assertCountAtLeast(1) } @@ -551,38 +572,42 @@ func Test_EthKeyStore_Enable(t *testing.T) { ks := keyStore.Eth() t.Run("already existing disabled key gets enabled", func(t *testing.T) { + ctx := testutils.Context(t) k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) - key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, ks.Add(ctx, k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Disable(ctx, k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(ctx, k.Address.Hex(), testutils.SimulatedChainID) require.NoError(t, err) require.Equal(t, key.Disabled, false) }) t.Run("creates key, deletes it unsafely and then enable creates it again", func(t *testing.T) { + ctx := testutils.Context(t) k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k.Address, testutils.SimulatedChainID)) _, err := db.Exec("DELETE FROM evm.key_states WHERE address = $1", k.Address) require.NoError(t, err) - require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) - key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, ks.Enable(ctx, k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(ctx, k.Address.Hex(), testutils.SimulatedChainID) require.NoError(t, err) require.Equal(t, key.Disabled, false) }) t.Run("creates key and enables it if it exists in the keystore, but is missing from key states db table", func(t *testing.T) { + ctx := testutils.Context(t) k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Enable(k.Address, testutils.SimulatedChainID)) - key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, ks.Enable(ctx, k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(ctx, k.Address.Hex(), testutils.SimulatedChainID) require.NoError(t, err) require.Equal(t, key.Disabled, false) }) t.Run("errors if key is not present in keystore", func(t *testing.T) { + ctx := testutils.Context(t) addrNotInKs := testutils.NewAddress() - require.Error(t, ks.Enable(addrNotInKs, testutils.SimulatedChainID)) - _, err := ks.GetState(addrNotInKs.Hex(), testutils.SimulatedChainID) + require.Error(t, ks.Enable(ctx, addrNotInKs, testutils.SimulatedChainID)) + _, err := ks.GetState(ctx, addrNotInKs.Hex(), testutils.SimulatedChainID) require.Error(t, err) }) } @@ -591,69 +616,72 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { t.Parallel() t.Run("creates one unique key per chain if none exist", func(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() testutils.AssertCount(t, db, "evm.key_states", 0) - err := ks.EnsureKeys(testutils.FixtureChainID, testutils.SimulatedChainID) + err := ks.EnsureKeys(ctx, testutils.FixtureChainID, testutils.SimulatedChainID) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 2) - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 2) }) t.Run("does nothing if a key exists for a chain", func(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() // Add one enabled key - _, err := ks.Create(testutils.FixtureChainID) + _, err := ks.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 1) - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 1) // this adds one more key for the additional chain - err = ks.EnsureKeys(testutils.FixtureChainID, testutils.SimulatedChainID) + err = ks.EnsureKeys(ctx, testutils.FixtureChainID, testutils.SimulatedChainID) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 2) - keys, err = ks.GetAll() + keys, err = ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 2) }) t.Run("does nothing if a key exists but is disabled for a chain", func(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() // Add one enabled key - k, err := ks.Create(testutils.FixtureChainID) + k, err := ks.Create(ctx, testutils.FixtureChainID) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 1) - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 1) // disable the key - err = ks.Disable(k.Address, testutils.FixtureChainID) + err = ks.Disable(ctx, k.Address, testutils.FixtureChainID) require.NoError(t, err) // this does nothing - err = ks.EnsureKeys(testutils.FixtureChainID) + err = ks.EnsureKeys(ctx, testutils.FixtureChainID) require.NoError(t, err) testutils.AssertCount(t, db, "evm.key_states", 1) - keys, err = ks.GetAll() + keys, err = ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 1) - state, err := ks.GetState(k.Address.Hex(), testutils.FixtureChainID) + state, err := ks.GetState(ctx, k.Address.Hex(), testutils.FixtureChainID) require.NoError(t, err) assert.True(t, state.Disabled) }) @@ -662,52 +690,56 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { func Test_EthKeyStore_Delete(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) ks := keyStore.Eth() randKeyID := utils.RandomAddress().Hex() - _, err := ks.Delete(randKeyID) + _, err := ks.Delete(ctx, randKeyID) require.Error(t, err) assert.Contains(t, err.Error(), "Key not found") _, addr1 := cltest.MustInsertRandomKey(t, ks) _, addr2 := cltest.MustInsertRandomKey(t, ks) cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.SimulatedChainID)) - require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, addr1, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, addr1, testutils.SimulatedChainID)) testutils.AssertCount(t, db, "evm.key_states", 4) - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 3) - _, err = ks.GetState(addr1.Hex(), testutils.FixtureChainID) + _, err = ks.GetState(ctx, addr1.Hex(), testutils.FixtureChainID) require.NoError(t, err) - _, err = ks.GetState(addr1.Hex(), testutils.SimulatedChainID) + _, err = ks.GetState(ctx, addr1.Hex(), testutils.SimulatedChainID) require.NoError(t, err) - deletedK, err := ks.Delete(addr1.String()) + deletedK, err := ks.Delete(ctx, addr1.String()) require.NoError(t, err) assert.Equal(t, addr1, deletedK.Address) testutils.AssertCount(t, db, "evm.key_states", 2) - keys, err = ks.GetAll() + keys, err = ks.GetAll(ctx) require.NoError(t, err) assert.Len(t, keys, 2) - _, err = ks.GetState(addr1.Hex(), testutils.FixtureChainID) + _, err = ks.GetState(ctx, addr1.Hex(), testutils.FixtureChainID) require.Error(t, err) assert.Contains(t, err.Error(), fmt.Sprintf("state not found for eth key ID %s", addr1.Hex())) - _, err = ks.GetState(addr1.Hex(), testutils.SimulatedChainID) + _, err = ks.GetState(ctx, addr1.Hex(), testutils.SimulatedChainID) require.Error(t, err) assert.Contains(t, err.Error(), fmt.Sprintf("state not found for eth key ID %s", addr1.Hex())) - _, err = ks.GetState(addr2.Hex(), testutils.FixtureChainID) + _, err = ks.GetState(ctx, addr2.Hex(), testutils.FixtureChainID) require.NoError(t, err) } func Test_EthKeyStore_CheckEnabled(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) @@ -725,29 +757,30 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { // - key 4 // enabled - fixture k1, addr1 := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k1.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Add(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Add(ctx, k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx, k1.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, k1.Address, testutils.FixtureChainID)) k2, addr2 := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k2.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Add(k2.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(k2.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k2.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Disable(k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k2.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Add(ctx, k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, k2.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx, k2.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Disable(ctx, k2.Address, testutils.SimulatedChainID)) k3, addr3 := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k3.Address, testutils.SimulatedChainID)) - require.NoError(t, ks.Enable(k3.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k3.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Enable(ctx, k3.Address, testutils.SimulatedChainID)) t.Run("enabling the same key multiple times does not create duplicate states", func(t *testing.T) { - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) - require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) + ctx2 := testutils.Context(t) + require.NoError(t, ks.Enable(ctx2, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx2, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx2, k1.Address, testutils.FixtureChainID)) + require.NoError(t, ks.Enable(ctx2, k1.Address, testutils.FixtureChainID)) - states, err := ks.GetStatesForKeys([]ethkey.KeyV2{k1}) + states, err := ks.GetStatesForKeys(ctx2, []ethkey.KeyV2{k1}) require.NoError(t, err) assert.Len(t, states, 2) var cids []*big.Int @@ -764,27 +797,27 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { }) t.Run("returns nil when key is enabled for given chain", func(t *testing.T) { - err := ks.CheckEnabled(addr1, testutils.FixtureChainID) + err := ks.CheckEnabled(ctx, addr1, testutils.FixtureChainID) assert.NoError(t, err) - err = ks.CheckEnabled(addr1, testutils.SimulatedChainID) + err = ks.CheckEnabled(ctx, addr1, testutils.SimulatedChainID) assert.NoError(t, err) }) t.Run("returns error when key does not exist", func(t *testing.T) { addr := utils.RandomAddress() - err := ks.CheckEnabled(addr, testutils.FixtureChainID) + err := ks.CheckEnabled(ctx, addr, testutils.FixtureChainID) assert.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("no eth key exists with address %s", addr.Hex())) }) t.Run("returns error when key exists but has never been enabled (no state) for the given chain", func(t *testing.T) { - err := ks.CheckEnabled(addr3, testutils.FixtureChainID) + err := ks.CheckEnabled(ctx, addr3, testutils.FixtureChainID) assert.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("eth key with address %s exists but is has not been enabled for chain 0 (enabled only for chain IDs: 1337)", addr3.Hex())) }) t.Run("returns error when key exists but is disabled for the given chain", func(t *testing.T) { - err := ks.CheckEnabled(addr2, testutils.SimulatedChainID) + err := ks.CheckEnabled(ctx, addr2, testutils.SimulatedChainID) assert.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("eth key with address %s exists but is disabled for chain 1337 (enabled only for chain IDs: 0)", addr2.Hex())) }) @@ -799,28 +832,31 @@ func Test_EthKeyStore_Disable(t *testing.T) { ks := keyStore.Eth() t.Run("creates key, deletes it unsafely and then enable creates it again", func(t *testing.T) { + ctx := testutils.Context(t) k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Add(k.Address, testutils.SimulatedChainID)) + require.NoError(t, ks.Add(ctx, k.Address, testutils.SimulatedChainID)) _, err := db.Exec("DELETE FROM evm.key_states WHERE address = $1", k.Address) require.NoError(t, err) - require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) - key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, ks.Disable(ctx, k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(ctx, k.Address.Hex(), testutils.SimulatedChainID) require.NoError(t, err) require.Equal(t, key.Disabled, true) }) t.Run("creates key and enables it if it exists in the keystore, but is missing from key states db table", func(t *testing.T) { + ctx := testutils.Context(t) k, _ := cltest.MustInsertRandomKeyNoChains(t, ks) - require.NoError(t, ks.Disable(k.Address, testutils.SimulatedChainID)) - key, err := ks.GetState(k.Address.Hex(), testutils.SimulatedChainID) + require.NoError(t, ks.Disable(ctx, k.Address, testutils.SimulatedChainID)) + key, err := ks.GetState(ctx, k.Address.Hex(), testutils.SimulatedChainID) require.NoError(t, err) require.Equal(t, key.Disabled, true) }) t.Run("errors if key is not present in keystore", func(t *testing.T) { + ctx := testutils.Context(t) addrNotInKs := testutils.NewAddress() - require.Error(t, ks.Disable(addrNotInKs, testutils.SimulatedChainID)) - _, err := ks.GetState(addrNotInKs.Hex(), testutils.SimulatedChainID) + require.Error(t, ks.Disable(ctx, addrNotInKs, testutils.SimulatedChainID)) + _, err := ks.GetState(ctx, addrNotInKs.Hex(), testutils.SimulatedChainID) require.Error(t, err) }) } diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index b3827398fd5..a5dd612d9e5 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -3,9 +3,11 @@ package mocks import ( + context "context" big "math/big" common "github.com/ethereum/go-ethereum/common" + ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mock "github.com/stretchr/testify/mock" @@ -20,14 +22,14 @@ type Eth struct { mock.Mock } -// Add provides a mock function with given fields: address, chainID, qopts -func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +// Add provides a mock function with given fields: ctx, address, chainID, qopts +func (_m *Eth) Add(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] } var _ca []interface{} - _ca = append(_ca, address, chainID) + _ca = append(_ca, ctx, address, chainID) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -36,8 +38,8 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { + r0 = rf(ctx, address, chainID, qopts...) } else { r0 = ret.Error(0) } @@ -45,17 +47,17 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e return r0 } -// CheckEnabled provides a mock function with given fields: address, chainID -func (_m *Eth) CheckEnabled(address common.Address, chainID *big.Int) error { - ret := _m.Called(address, chainID) +// CheckEnabled provides a mock function with given fields: ctx, address, chainID +func (_m *Eth) CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { panic("no return value specified for CheckEnabled") } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int) error); ok { - r0 = rf(address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) error); ok { + r0 = rf(ctx, address, chainID) } else { r0 = ret.Error(0) } @@ -63,13 +65,14 @@ func (_m *Eth) CheckEnabled(address common.Address, chainID *big.Int) error { return r0 } -// Create provides a mock function with given fields: chainIDs -func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { +// Create provides a mock function with given fields: ctx, chainIDs +func (_m *Eth) Create(ctx context.Context, chainIDs ...*big.Int) (ethkey.KeyV2, error) { _va := make([]interface{}, len(chainIDs)) for _i := range chainIDs { _va[_i] = chainIDs[_i] } var _ca []interface{} + _ca = append(_ca, ctx) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -79,17 +82,17 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { var r0 ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(...*big.Int) (ethkey.KeyV2, error)); ok { - return rf(chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, ...*big.Int) (ethkey.KeyV2, error)); ok { + return rf(ctx, chainIDs...) } - if rf, ok := ret.Get(0).(func(...*big.Int) ethkey.KeyV2); ok { - r0 = rf(chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, ...*big.Int) ethkey.KeyV2); ok { + r0 = rf(ctx, chainIDs...) } else { r0 = ret.Get(0).(ethkey.KeyV2) } - if rf, ok := ret.Get(1).(func(...*big.Int) error); ok { - r1 = rf(chainIDs...) + if rf, ok := ret.Get(1).(func(context.Context, ...*big.Int) error); ok { + r1 = rf(ctx, chainIDs...) } else { r1 = ret.Error(1) } @@ -97,9 +100,9 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { return r0, r1 } -// Delete provides a mock function with given fields: id -func (_m *Eth) Delete(id string) (ethkey.KeyV2, error) { - ret := _m.Called(id) +// Delete provides a mock function with given fields: ctx, id +func (_m *Eth) Delete(ctx context.Context, id string) (ethkey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") @@ -107,17 +110,17 @@ func (_m *Eth) Delete(id string) (ethkey.KeyV2, error) { var r0 ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (ethkey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) ethkey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) ethkey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(ethkey.KeyV2) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -125,14 +128,14 @@ func (_m *Eth) Delete(id string) (ethkey.KeyV2, error) { return r0, r1 } -// Disable provides a mock function with given fields: address, chainID, qopts -func (_m *Eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +// Disable provides a mock function with given fields: ctx, address, chainID, qopts +func (_m *Eth) Disable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] } var _ca []interface{} - _ca = append(_ca, address, chainID) + _ca = append(_ca, ctx, address, chainID) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -141,8 +144,8 @@ func (_m *Eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { + r0 = rf(ctx, address, chainID, qopts...) } else { r0 = ret.Error(0) } @@ -150,14 +153,14 @@ func (_m *Eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp return r0 } -// Enable provides a mock function with given fields: address, chainID, qopts -func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { +// Enable provides a mock function with given fields: ctx, address, chainID, qopts +func (_m *Eth) Enable(ctx context.Context, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] } var _ca []interface{} - _ca = append(_ca, address, chainID) + _ca = append(_ca, ctx, address, chainID) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -166,8 +169,8 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt } var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int, ...pg.QOpt) error); ok { + r0 = rf(ctx, address, chainID, qopts...) } else { r0 = ret.Error(0) } @@ -175,9 +178,9 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt return r0 } -// EnabledAddressesForChain provides a mock function with given fields: chainID -func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, error) { - ret := _m.Called(chainID) +// EnabledAddressesForChain provides a mock function with given fields: ctx, chainID +func (_m *Eth) EnabledAddressesForChain(ctx context.Context, chainID *big.Int) ([]common.Address, error) { + ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for EnabledAddressesForChain") @@ -185,19 +188,19 @@ func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, err var r0 []common.Address var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]common.Address, error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]common.Address, error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []common.Address); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []common.Address); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]common.Address) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -205,9 +208,9 @@ func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, err return r0, r1 } -// EnabledKeysForChain provides a mock function with given fields: chainID -func (_m *Eth) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { - ret := _m.Called(chainID) +// EnabledKeysForChain provides a mock function with given fields: ctx, chainID +func (_m *Eth) EnabledKeysForChain(ctx context.Context, chainID *big.Int) ([]ethkey.KeyV2, error) { + ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for EnabledKeysForChain") @@ -215,19 +218,19 @@ func (_m *Eth) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { var r0 []ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]ethkey.KeyV2, error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []ethkey.KeyV2); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []ethkey.KeyV2); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.KeyV2) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -235,13 +238,14 @@ func (_m *Eth) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { return r0, r1 } -// EnsureKeys provides a mock function with given fields: chainIDs -func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { +// EnsureKeys provides a mock function with given fields: ctx, chainIDs +func (_m *Eth) EnsureKeys(ctx context.Context, chainIDs ...*big.Int) error { _va := make([]interface{}, len(chainIDs)) for _i := range chainIDs { _va[_i] = chainIDs[_i] } var _ca []interface{} + _ca = append(_ca, ctx) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -250,8 +254,8 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { } var r0 error - if rf, ok := ret.Get(0).(func(...*big.Int) error); ok { - r0 = rf(chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, ...*big.Int) error); ok { + r0 = rf(ctx, chainIDs...) } else { r0 = ret.Error(0) } @@ -259,9 +263,9 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { return r0 } -// Export provides a mock function with given fields: id, password -func (_m *Eth) Export(id string, password string) ([]byte, error) { - ret := _m.Called(id, password) +// Export provides a mock function with given fields: ctx, id, password +func (_m *Eth) Export(ctx context.Context, id string, password string) ([]byte, error) { + ret := _m.Called(ctx, id, password) if len(ret) == 0 { panic("no return value specified for Export") @@ -269,19 +273,19 @@ func (_m *Eth) Export(id string, password string) ([]byte, error) { var r0 []byte var r1 error - if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { - return rf(id, password) + if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]byte, error)); ok { + return rf(ctx, id, password) } - if rf, ok := ret.Get(0).(func(string, string) []byte); ok { - r0 = rf(id, password) + if rf, ok := ret.Get(0).(func(context.Context, string, string) []byte); ok { + r0 = rf(ctx, id, password) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]byte) } } - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(id, password) + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, id, password) } else { r1 = ret.Error(1) } @@ -289,9 +293,9 @@ func (_m *Eth) Export(id string, password string) ([]byte, error) { return r0, r1 } -// Get provides a mock function with given fields: id -func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { - ret := _m.Called(id) +// Get provides a mock function with given fields: ctx, id +func (_m *Eth) Get(ctx context.Context, id string) (ethkey.KeyV2, error) { + ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Get") @@ -299,17 +303,17 @@ func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { var r0 ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { - return rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) (ethkey.KeyV2, error)); ok { + return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(string) ethkey.KeyV2); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(context.Context, string) ethkey.KeyV2); ok { + r0 = rf(ctx, id) } else { r0 = ret.Get(0).(ethkey.KeyV2) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) } else { r1 = ret.Error(1) } @@ -317,9 +321,9 @@ func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { return r0, r1 } -// GetAll provides a mock function with given fields: -func (_m *Eth) GetAll() ([]ethkey.KeyV2, error) { - ret := _m.Called() +// GetAll provides a mock function with given fields: ctx +func (_m *Eth) GetAll(ctx context.Context) ([]ethkey.KeyV2, error) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetAll") @@ -327,19 +331,19 @@ func (_m *Eth) GetAll() ([]ethkey.KeyV2, error) { var r0 []ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func() ([]ethkey.KeyV2, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) ([]ethkey.KeyV2, error)); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() []ethkey.KeyV2); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) []ethkey.KeyV2); ok { + r0 = rf(ctx) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.KeyV2) } } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { r1 = ret.Error(1) } @@ -347,14 +351,14 @@ func (_m *Eth) GetAll() ([]ethkey.KeyV2, error) { return r0, r1 } -// GetRoundRobinAddress provides a mock function with given fields: chainID, addresses -func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Address) (common.Address, error) { +// GetRoundRobinAddress provides a mock function with given fields: ctx, chainID, addresses +func (_m *Eth) GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (common.Address, error) { _va := make([]interface{}, len(addresses)) for _i := range addresses { _va[_i] = addresses[_i] } var _ca []interface{} - _ca = append(_ca, chainID) + _ca = append(_ca, ctx, chainID) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -364,19 +368,19 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres var r0 common.Address var r1 error - if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { - return rf(chainID, addresses...) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) (common.Address, error)); ok { + return rf(ctx, chainID, addresses...) } - if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) common.Address); ok { - r0 = rf(chainID, addresses...) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) common.Address); ok { + r0 = rf(ctx, chainID, addresses...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.Address) } } - if rf, ok := ret.Get(1).(func(*big.Int, ...common.Address) error); ok { - r1 = rf(chainID, addresses...) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int, ...common.Address) error); ok { + r1 = rf(ctx, chainID, addresses...) } else { r1 = ret.Error(1) } @@ -384,9 +388,9 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres return r0, r1 } -// GetState provides a mock function with given fields: id, chainID -func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { - ret := _m.Called(id, chainID) +// GetState provides a mock function with given fields: ctx, id, chainID +func (_m *Eth) GetState(ctx context.Context, id string, chainID *big.Int) (ethkey.State, error) { + ret := _m.Called(ctx, id, chainID) if len(ret) == 0 { panic("no return value specified for GetState") @@ -394,17 +398,17 @@ func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { var r0 ethkey.State var r1 error - if rf, ok := ret.Get(0).(func(string, *big.Int) (ethkey.State, error)); ok { - return rf(id, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, *big.Int) (ethkey.State, error)); ok { + return rf(ctx, id, chainID) } - if rf, ok := ret.Get(0).(func(string, *big.Int) ethkey.State); ok { - r0 = rf(id, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, *big.Int) ethkey.State); ok { + r0 = rf(ctx, id, chainID) } else { r0 = ret.Get(0).(ethkey.State) } - if rf, ok := ret.Get(1).(func(string, *big.Int) error); ok { - r1 = rf(id, chainID) + if rf, ok := ret.Get(1).(func(context.Context, string, *big.Int) error); ok { + r1 = rf(ctx, id, chainID) } else { r1 = ret.Error(1) } @@ -412,9 +416,9 @@ func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { return r0, r1 } -// GetStateForKey provides a mock function with given fields: _a0 -func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { - ret := _m.Called(_a0) +// GetStateForKey provides a mock function with given fields: ctx, key +func (_m *Eth) GetStateForKey(ctx context.Context, key ethkey.KeyV2) (ethkey.State, error) { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for GetStateForKey") @@ -422,17 +426,17 @@ func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { var r0 ethkey.State var r1 error - if rf, ok := ret.Get(0).(func(ethkey.KeyV2) (ethkey.State, error)); ok { - return rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, ethkey.KeyV2) (ethkey.State, error)); ok { + return rf(ctx, key) } - if rf, ok := ret.Get(0).(func(ethkey.KeyV2) ethkey.State); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, ethkey.KeyV2) ethkey.State); ok { + r0 = rf(ctx, key) } else { r0 = ret.Get(0).(ethkey.State) } - if rf, ok := ret.Get(1).(func(ethkey.KeyV2) error); ok { - r1 = rf(_a0) + if rf, ok := ret.Get(1).(func(context.Context, ethkey.KeyV2) error); ok { + r1 = rf(ctx, key) } else { r1 = ret.Error(1) } @@ -440,9 +444,9 @@ func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { return r0, r1 } -// GetStatesForChain provides a mock function with given fields: chainID -func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { - ret := _m.Called(chainID) +// GetStatesForChain provides a mock function with given fields: ctx, chainID +func (_m *Eth) GetStatesForChain(ctx context.Context, chainID *big.Int) ([]ethkey.State, error) { + ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for GetStatesForChain") @@ -450,19 +454,19 @@ func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { var r0 []ethkey.State var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.State, error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]ethkey.State, error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []ethkey.State); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []ethkey.State); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.State) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -470,9 +474,9 @@ func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { return r0, r1 } -// GetStatesForKeys provides a mock function with given fields: _a0 -func (_m *Eth) GetStatesForKeys(_a0 []ethkey.KeyV2) ([]ethkey.State, error) { - ret := _m.Called(_a0) +// GetStatesForKeys provides a mock function with given fields: ctx, keys +func (_m *Eth) GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) ([]ethkey.State, error) { + ret := _m.Called(ctx, keys) if len(ret) == 0 { panic("no return value specified for GetStatesForKeys") @@ -480,19 +484,19 @@ func (_m *Eth) GetStatesForKeys(_a0 []ethkey.KeyV2) ([]ethkey.State, error) { var r0 []ethkey.State var r1 error - if rf, ok := ret.Get(0).(func([]ethkey.KeyV2) ([]ethkey.State, error)); ok { - return rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, []ethkey.KeyV2) ([]ethkey.State, error)); ok { + return rf(ctx, keys) } - if rf, ok := ret.Get(0).(func([]ethkey.KeyV2) []ethkey.State); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, []ethkey.KeyV2) []ethkey.State); ok { + r0 = rf(ctx, keys) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.State) } } - if rf, ok := ret.Get(1).(func([]ethkey.KeyV2) error); ok { - r1 = rf(_a0) + if rf, ok := ret.Get(1).(func(context.Context, []ethkey.KeyV2) error); ok { + r1 = rf(ctx, keys) } else { r1 = ret.Error(1) } @@ -500,14 +504,14 @@ func (_m *Eth) GetStatesForKeys(_a0 []ethkey.KeyV2) ([]ethkey.State, error) { return r0, r1 } -// Import provides a mock function with given fields: keyJSON, password, chainIDs -func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) { +// Import provides a mock function with given fields: ctx, keyJSON, password, chainIDs +func (_m *Eth) Import(ctx context.Context, keyJSON []byte, password string, chainIDs ...*big.Int) (ethkey.KeyV2, error) { _va := make([]interface{}, len(chainIDs)) for _i := range chainIDs { _va[_i] = chainIDs[_i] } var _ca []interface{} - _ca = append(_ca, keyJSON, password) + _ca = append(_ca, ctx, keyJSON, password) _ca = append(_ca, _va...) ret := _m.Called(_ca...) @@ -517,17 +521,17 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et var r0 ethkey.KeyV2 var r1 error - if rf, ok := ret.Get(0).(func([]byte, string, ...*big.Int) (ethkey.KeyV2, error)); ok { - return rf(keyJSON, password, chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string, ...*big.Int) (ethkey.KeyV2, error)); ok { + return rf(ctx, keyJSON, password, chainIDs...) } - if rf, ok := ret.Get(0).(func([]byte, string, ...*big.Int) ethkey.KeyV2); ok { - r0 = rf(keyJSON, password, chainIDs...) + if rf, ok := ret.Get(0).(func(context.Context, []byte, string, ...*big.Int) ethkey.KeyV2); ok { + r0 = rf(ctx, keyJSON, password, chainIDs...) } else { r0 = ret.Get(0).(ethkey.KeyV2) } - if rf, ok := ret.Get(1).(func([]byte, string, ...*big.Int) error); ok { - r1 = rf(keyJSON, password, chainIDs...) + if rf, ok := ret.Get(1).(func(context.Context, []byte, string, ...*big.Int) error); ok { + r1 = rf(ctx, keyJSON, password, chainIDs...) } else { r1 = ret.Error(1) } @@ -535,9 +539,9 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et return r0, r1 } -// SignTx provides a mock function with given fields: fromAddress, tx, chainID -func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - ret := _m.Called(fromAddress, tx, chainID) +// SignTx provides a mock function with given fields: ctx, fromAddress, tx, chainID +func (_m *Eth) SignTx(ctx context.Context, fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + ret := _m.Called(ctx, fromAddress, tx, chainID) if len(ret) == 0 { panic("no return value specified for SignTx") @@ -545,19 +549,19 @@ func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { - return rf(fromAddress, tx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { + return rf(ctx, fromAddress, tx, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) *types.Transaction); ok { - r0 = rf(fromAddress, tx, chainID) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *types.Transaction, *big.Int) *types.Transaction); ok { + r0 = rf(ctx, fromAddress, tx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(common.Address, *types.Transaction, *big.Int) error); ok { - r1 = rf(fromAddress, tx, chainID) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *types.Transaction, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, tx, chainID) } else { r1 = ret.Error(1) } @@ -565,9 +569,9 @@ func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID return r0, r1 } -// SubscribeToKeyChanges provides a mock function with given fields: -func (_m *Eth) SubscribeToKeyChanges() (chan struct{}, func()) { - ret := _m.Called() +// SubscribeToKeyChanges provides a mock function with given fields: ctx +func (_m *Eth) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { + ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for SubscribeToKeyChanges") @@ -575,19 +579,19 @@ func (_m *Eth) SubscribeToKeyChanges() (chan struct{}, func()) { var r0 chan struct{} var r1 func() - if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (chan struct{}, func())); ok { + return rf(ctx) } - if rf, ok := ret.Get(0).(func() chan struct{}); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) chan struct{}); ok { + r0 = rf(ctx) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(chan struct{}) } } - if rf, ok := ret.Get(1).(func() func()); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) func()); ok { + r1 = rf(ctx) } else { if ret.Get(1) != nil { r1 = ret.Get(1).(func()) @@ -597,14 +601,14 @@ func (_m *Eth) SubscribeToKeyChanges() (chan struct{}, func()) { return r0, r1 } -// XXXTestingOnlyAdd provides a mock function with given fields: key -func (_m *Eth) XXXTestingOnlyAdd(key ethkey.KeyV2) { - _m.Called(key) +// XXXTestingOnlyAdd provides a mock function with given fields: ctx, key +func (_m *Eth) XXXTestingOnlyAdd(ctx context.Context, key ethkey.KeyV2) { + _m.Called(ctx, key) } -// XXXTestingOnlySetState provides a mock function with given fields: _a0 -func (_m *Eth) XXXTestingOnlySetState(_a0 ethkey.State) { - _m.Called(_a0) +// XXXTestingOnlySetState provides a mock function with given fields: ctx, keyState +func (_m *Eth) XXXTestingOnlySetState(ctx context.Context, keyState ethkey.State) { + _m.Called(ctx, keyState) } // NewEth creates a new instance of Eth. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 0eed680a3d8..6d7757ea528 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -1,6 +1,7 @@ package ocr import ( + "context" "fmt" "strings" "time" @@ -87,7 +88,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the OCR services that need to run for this job -func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { if jb.OCROracleSpec == nil { return nil, errors.Errorf("offchainreporting.Delegate expects an *job.OffchainreportingOracleSpec to be present, got %v", jb) } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 336d1ae3800..8677f48e8b5 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -352,7 +352,7 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error } // ServicesForSpec returns the OCR2 services that need to run for this job -func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { spec := jb.OCR2OracleSpec if spec == nil { return nil, errors.Errorf("offchainreporting2.Delegate expects an *job.OCR2OracleSpec to be present, got %v", jb) @@ -438,7 +438,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { spec.CaptureEATelemetry = d.cfg.OCR2().CaptureEATelemetry() - ctx := lggrCtx.ContextWithValues(context.Background()) + ctx = lggrCtx.ContextWithValues(ctx) switch spec.PluginType { case types.Mercury: return d.newServicesMercury(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) @@ -466,7 +466,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { ) thresholdPluginDB := NewDB(d.db, spec.ID, thresholdPluginId, lggr, d.cfg.Database()) s4PluginDB := NewDB(d.db, spec.ID, s4PluginId, lggr, d.cfg.Database()) - return d.newServicesOCR2Functions(lggr, jb, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) + return d.newServicesOCR2Functions(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) case types.GenericPlugin: return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, d.capabilitiesRegistry) @@ -1510,6 +1510,7 @@ func (d *Delegate) newServicesOCR2Keepers20( } func (d *Delegate) newServicesOCR2Functions( + ctx context.Context, lggr logger.SugaredLogger, jb job.Job, bootstrapPeers []commontypes.BootstrapperLocator, @@ -1535,6 +1536,7 @@ func (d *Delegate) newServicesOCR2Functions( } createPluginProvider := func(pluginType functionsRelay.FunctionsPluginType, relayerName string) (evmrelaytypes.FunctionsProvider, error) { return evmrelay.NewFunctionsProvider( + ctx, chain, types.RelayArgs{ ExternalJobID: jb.ExternalJobID, @@ -1646,7 +1648,7 @@ func (d *Delegate) newServicesOCR2Functions( LogPollerWrapper: functionsProvider.LogPollerWrapper(), } - functionsServices, err := functions.NewFunctionsServices(&functionsOracleArgs, &thresholdOracleArgs, &s4OracleArgs, &functionsServicesConfig) + functionsServices, err := functions.NewFunctionsServices(ctx, &functionsOracleArgs, &thresholdOracleArgs, &s4OracleArgs, &functionsServicesConfig) if err != nil { return nil, errors.Wrap(err, "error calling NewFunctionsServices") } 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 3061d818bf1..7f562c9adb3 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 @@ -348,7 +348,7 @@ func StartNewNode( app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) require.Len(t, sendingKeys, 1) transmitter := sendingKeys[0].Address diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index a49ce4be90a..27835127d0d 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -1,6 +1,7 @@ package functions import ( + "context" "encoding/json" "math/big" "slices" @@ -59,7 +60,7 @@ const ( ) // Create all OCR2 plugin Oracles and all extra services needed to run a Functions job. -func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs *libocr2.OCR2OracleArgs, conf *FunctionsServicesConfig) ([]job.ServiceCtx, error) { +func NewFunctionsServices(ctx context.Context, functionsOracleArgs, thresholdOracleArgs, s4OracleArgs *libocr2.OCR2OracleArgs, conf *FunctionsServicesConfig) ([]job.ServiceCtx, error) { pluginORM := functions.NewORM(conf.DB, conf.Logger, conf.QConfig, common.HexToAddress(conf.ContractID)) s4ORM := s4.NewPostgresORM(conf.DB, conf.Logger, conf.QConfig, s4.SharedTableName, FunctionsS4Namespace) @@ -156,7 +157,7 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs 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, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, connectorLogger) + connector, err2 := NewConnector(ctx, &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") } @@ -183,8 +184,8 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs return allServices, nil } -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) +func NewConnector(ctx context.Context, 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(ctx, chainID) 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 cd7956240df..fdd20b0a932 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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" @@ -23,6 +24,9 @@ import ( func TestNewConnector_Success(t *testing.T) { t.Parallel() + + ctx := testutils.Context(t) + keyV2, err := ethkey.NewV2() require.NoError(t, err) @@ -39,16 +43,19 @@ func TestNewConnector_Success(t *testing.T) { require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) - ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) + ethKeystore.On("EnabledKeysForChain", mock.Anything, mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) config := &config.PluginConfig{ GatewayConnectorConfig: gwcCfg, } - _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) + _, err = functions.NewConnector(ctx, config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.NoError(t, err) } func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { t.Parallel() + + ctx := testutils.Context(t) + addresses := []string{ "0x00000000DE801ceE9471ADf23370c48b011f82a6", "0x11111111DE801ceE9471ADf23370c48b011f82a6", @@ -67,10 +74,10 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { 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) + ethKeystore.On("EnabledKeysForChain", mock.Anything, mock.Anything).Return([]ethkey.KeyV2{{Address: common.HexToAddress(addresses[1])}}, nil) config := &config.PluginConfig{ GatewayConnectorConfig: gwcCfg, } - _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) + _, err = functions.NewConnector(ctx, config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.Error(t, err) } 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 4a01ee7904f..8d50b8076bb 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -226,6 +226,7 @@ func setupNodeOCR2( useForwarders bool, p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { + ctx := testutils.Context(t) p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -255,7 +256,7 @@ func setupNodeOCR2( var sendingKeys []ethkey.KeyV2 { var err error - sendingKeys, err = app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + sendingKeys, err = app.KeyStore.Eth().EnabledKeysForChain(ctx, testutils.SimulatedChainID) require.NoError(t, err) require.Len(t, sendingKeys, 1) } @@ -266,10 +267,10 @@ func setupNodeOCR2( sendingKeysAddresses := []common.Address{sendingKeys[0].Address} // Add new sending key. - k, err := app.KeyStore.Eth().Create() + k, err := app.KeyStore.Eth().Create(ctx) require.NoError(t, err) - require.NoError(t, app.KeyStore.Eth().Add(k.Address, testutils.SimulatedChainID)) - require.NoError(t, app.KeyStore.Eth().Enable(k.Address, testutils.SimulatedChainID)) + require.NoError(t, app.KeyStore.Eth().Add(ctx, k.Address, testutils.SimulatedChainID)) + require.NoError(t, app.KeyStore.Eth().Enable(ctx, k.Address, testutils.SimulatedChainID)) sendingKeys = append(sendingKeys, k) sendingKeysAddresses = append(sendingKeysAddresses, k.Address) @@ -296,7 +297,7 @@ func setupNodeOCR2( var sendingKeyStrings []string for _, k := range sendingKeys { sendingKeyStrings = append(sendingKeyStrings, k.Address.String()) - n, err := b.NonceAt(testutils.Context(t), owner.From, nil) + n, err := b.NonceAt(ctx, owner.From, nil) require.NoError(t, err) tx := cltest.NewLegacyTransaction( @@ -307,7 +308,7 @@ func setupNodeOCR2( nil) signedTx, err := owner.Signer(owner.From, tx) require.NoError(t, err) - err = b.SendTransaction(testutils.Context(t), signedTx) + err = b.SendTransaction(ctx, signedTx) require.NoError(t, err) b.Commit() } @@ -429,7 +430,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { ) t.Log("Adding bootstrap node job") - err = bootstrapNode.app.Start(testutils.Context(t)) + err = bootstrapNode.app.Start(ctx) require.NoError(t, err) evmChains := bootstrapNode.app.GetRelayers().LegacyEVMChains() @@ -457,7 +458,7 @@ fromBlock = %d for x := 1; x < len(sendingKeys[i]); x++ { sendingKeysString = fmt.Sprintf(`%s,"%s"`, sendingKeysString, sendingKeys[i][x]) } - err = apps[i].Start(testutils.Context(t)) + err = apps[i].Start(ctx) require.NoError(t, err) jobSpec := fmt.Sprintf(` @@ -511,7 +512,7 @@ linkEthFeedAddress = "%s" emptyHash := crypto.Keccak256Hash(emptyKH[:]) gomega.NewWithT(t).Eventually(func() bool { kh, err2 := uni.beacon.SProvingKeyHash(&bind.CallOpts{ - Context: testutils.Context(t), + Context: ctx, }) require.NoError(t, err2) t.Log("proving keyhash:", hexutil.Encode(kh[:])) @@ -661,7 +662,7 @@ linkEthFeedAddress = "%s" totalNopPayout := new(big.Int) for idx, payeeTransactor := range payeeTransactors { // Fund the payee with some ETH. - n, err2 := uni.backend.NonceAt(testutils.Context(t), uni.owner.From, nil) + n, err2 := uni.backend.NonceAt(ctx, uni.owner.From, nil) require.NoError(t, err2) tx := cltest.NewLegacyTransaction( n, payeeTransactor.From, @@ -671,7 +672,7 @@ linkEthFeedAddress = "%s" nil) signedTx, err2 := uni.owner.Signer(uni.owner.From, tx) require.NoError(t, err2) - err2 = uni.backend.SendTransaction(testutils.Context(t), signedTx) + err2 = uni.backend.SendTransaction(ctx, signedTx) require.NoError(t, err2) _, err2 = uni.beacon.WithdrawPayment(payeeTransactor, transmitters[idx]) diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index 27ddd53bd52..46c664007bc 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -79,7 +79,7 @@ func (d *Delegate) BeforeJobCreated(spec job.Job) { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { spec := jb.BootstrapSpec if spec == nil { return nil, errors.Errorf("Bootstrap.Delegate expects an *job.BootstrapSpec to be present, got %v", jb) @@ -109,7 +109,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e ContractID: spec.ContractID, FeedID: spec.FeedID, } - ctx := ctxVals.ContextWithValues(context.Background()) + ctx = ctxVals.ContextWithValues(ctx) var relayCfg relayConfig if err = json.Unmarshal(spec.RelayConfig.Bytes(), &relayCfg); err != nil { diff --git a/core/services/ocrcommon/transmitter.go b/core/services/ocrcommon/transmitter.go index 9cdf6a0c5a9..1c4173798ea 100644 --- a/core/services/ocrcommon/transmitter.go +++ b/core/services/ocrcommon/transmitter.go @@ -12,7 +12,7 @@ import ( ) type roundRobinKeystore interface { - GetRoundRobinAddress(chainID *big.Int, addresses ...common.Address) (address common.Address, err error) + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (address common.Address, err error) } type txManager interface { @@ -66,7 +66,7 @@ func NewTransmitter( func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(t.chainID, t.fromAddresses...) + roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...) if err != nil { return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") } diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index 1687c974140..ffd496c486d 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -47,7 +47,7 @@ type ETHTxTask struct { } type ETHKeyStore interface { - GetRoundRobinAddress(chainID *big.Int, addrs ...common.Address) (common.Address, error) + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addrs ...common.Address) (common.Address, error) } var _ Task = (*ETHTxTask)(nil) @@ -127,7 +127,7 @@ func (t *ETHTxTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inpu return Result{Error: err}, runInfo } - fromAddr, err := t.keyStore.GetRoundRobinAddress(chain.ID(), fromAddrs...) + fromAddr, err := t.keyStore.GetRoundRobinAddress(ctx, chain.ID(), fromAddrs...) if err != nil { err = errors.Wrap(err, "ETHTxTask failed to get fromAddress") lggr.Error(err) diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index 5f5019d1967..d50949e120d 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -83,7 +83,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -131,7 +131,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -169,7 +169,7 @@ func TestETHTxTask(t *testing.T) { nil, func(keyStore *keystoremocks.Eth, txManager *txmmocks.MockEvmTxManager) { addr := common.HexToAddress("0x882969652440ccf14a5dbb9bd53eb21cb1e11e5c") - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, addr).Return(addr, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, addr).Return(addr, nil) txManager.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.MinConfirmations == clnull.Uint32From(2) })).Return(txmgr.Tx{}, nil) @@ -209,7 +209,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -255,7 +255,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -286,7 +286,7 @@ func TestETHTxTask(t *testing.T) { data := []byte("foobar") gasLimit := uint32(12345) txMeta := &txmgr.TxMeta{FailOnRevert: null.BoolFrom(false)} - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -321,7 +321,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -356,7 +356,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -395,7 +395,7 @@ func TestETHTxTask(t *testing.T) { nil, func(keyStore *keystoremocks.Eth, txManager *txmmocks.MockEvmTxManager) { - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID).Return(nil, errors.New("uh oh")) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID).Return(nil, errors.New("uh oh")) }, nil, pipeline.ErrTaskRunFailed, "while querying keystore", pipeline.RunInfo{IsRetryable: true}, }, @@ -422,7 +422,7 @@ func TestETHTxTask(t *testing.T) { RequestTxHash: &reqTxHash, FailOnRevert: null.BoolFrom(false), } - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, @@ -519,7 +519,7 @@ func TestETHTxTask(t *testing.T) { nil, func(keyStore *keystoremocks.Eth, txManager *txmmocks.MockEvmTxManager) { from := common.HexToAddress("0x882969652440ccf14a5dbb9bd53eb21cb1e11e5c") - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) + keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, from).Return(from, nil) txManager.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.MinConfirmations == clnull.Uint32From(3) && tx.PipelineTaskRunID != nil })).Return(txmgr.Tx{}, nil) diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index dcccbb90c79..a02885cb556 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -159,6 +159,10 @@ func (r *Relayer) HealthReport() (report map[string]error) { } func (r *Relayer) NewPluginProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.PluginProvider, error) { + + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + lggr := r.lggr.Named("PluginProvider").Named(rargs.ExternalJobID.String()) configWatcher, err := newStandardConfigProvider(r.lggr, r.chain, types.NewRelayOpts(rargs)) @@ -166,7 +170,7 @@ func (r *Relayer) NewPluginProvider(rargs commontypes.RelayArgs, pargs commontyp return nil, err } - transmitter, err := newOnChainContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + transmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } @@ -300,9 +304,13 @@ func (r *Relayer) NewLLOProvider(rargs commontypes.RelayArgs, pargs commontypes. } func (r *Relayer) NewFunctionsProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { + + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + lggr := r.lggr.Named("FunctionsProvider").Named(rargs.ExternalJobID.String()) // TODO(FUN-668): Not ready yet (doesn't implement FunctionsEvents() properly) - return NewFunctionsProvider(r.chain, rargs, pargs, lggr, r.ks.Eth(), functions.FunctionsPlugin) + return NewFunctionsProvider(ctx, r.chain, rargs, pargs, lggr, r.ks.Eth(), functions.FunctionsPlugin) } // NewConfigProvider is called by bootstrap jobs @@ -450,7 +458,7 @@ type configTransmitterOpts struct { pluginGasLimit *uint32 } -func newOnChainContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI) (*contractTransmitter, error) { +func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -473,7 +481,7 @@ func newOnChainContractTransmitter(lggr logger.Logger, rargs commontypes.RelayAr if sendingKeysLength > 1 && s == effectiveTransmitterAddress.String() { return nil, pkgerrors.New("the transmitter is a local sending key with transaction forwarding enabled") } - if err := ethKeystore.CheckEnabled(common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { + if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { return nil, pkgerrors.Wrap(err, "one of the sending keys given is not enabled") } fromAddresses = append(fromAddresses, common.HexToAddress(s)) @@ -523,6 +531,9 @@ func newOnChainContractTransmitter(lggr logger.Logger, rargs commontypes.RelayAr } func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MedianProvider, error) { + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() @@ -545,7 +556,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp reportCodec := evmreportcodec.ReportCodec{} - contractTransmitter, err := newOnChainContractTransmitter(lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + contractTransmitter, err := newOnChainContractTransmitter(ctx, lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index d4e91034496..c10134f3acc 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -90,7 +90,7 @@ 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) { +func NewFunctionsProvider(ctx context.Context, 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() if err != nil { @@ -121,7 +121,7 @@ func NewFunctionsProvider(chain legacyevm.Chain, rargs commontypes.RelayArgs, pa } var contractTransmitter ContractTransmitter if relayConfig.SendingKeys != nil { - contractTransmitter, err = newFunctionsContractTransmitter(pluginConfig.ContractVersion, rargs, pargs.TransmitterID, configWatcher, ethKeystore, logPollerWrapper, lggr) + contractTransmitter, err = newFunctionsContractTransmitter(ctx, pluginConfig.ContractVersion, rargs, pargs.TransmitterID, configWatcher, ethKeystore, logPollerWrapper, lggr) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, c return newConfigWatcher(lggr, routerContractAddress, offchainConfigDigester, cp, chain, fromBlock, args.New), nil } -func newFunctionsContractTransmitter(contractVersion uint32, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { +func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { var relayConfig evmRelayTypes.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -177,7 +177,7 @@ func newFunctionsContractTransmitter(contractVersion uint32, rargs commontypes.R if sendingKeysLength > 1 && s == effectiveTransmitterAddress.String() { return nil, errors.New("the transmitter is a local sending key with transaction forwarding enabled") } - if err := ethKeystore.CheckEnabled(common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { + if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { return nil, errors.Wrap(err, "one of the sending keys given is not enabled") } fromAddresses = append(fromAddresses, common.HexToAddress(s)) diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 6bde444d80b..6563604945c 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -84,13 +84,17 @@ func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger } func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2KeeperProvider, error) { + + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + cfgWatcher, err := newOCR2KeeperConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err } gasLimit := cfgWatcher.chain.Config().EVM().OCR2().Automation().GasLimit() - contractTransmitter, err := newOnChainContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}, OCR2AggregatorTransmissionContractABI) + contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index d421b38ea77..98753655550 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -1,6 +1,7 @@ package evm import ( + "context" "encoding/json" "fmt" @@ -59,11 +60,15 @@ func NewOCR2VRFRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, e } func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (DKGProvider, error) { + + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + configWatcher, err := newOCR2VRFConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err } - contractTransmitter, err := newOnChainContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } @@ -82,11 +87,15 @@ func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commo } func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2VRFProvider, error) { + + // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 + ctx := context.Background() + configWatcher, err := newOCR2VRFConfigProvider(r.lggr, r.chain, rargs) if err != nil { return nil, err } - contractTransmitter, err := newOnChainContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } diff --git a/core/services/streams/delegate.go b/core/services/streams/delegate.go index f7dc852a50b..5ea0d475d2b 100644 --- a/core/services/streams/delegate.go +++ b/core/services/streams/delegate.go @@ -43,7 +43,7 @@ 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) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { if jb.StreamID == nil { return nil, errors.New("streamID is required to be present for stream specs") } diff --git a/core/services/streams/delegate_test.go b/core/services/streams/delegate_test.go index e97da63d522..d177c977e1b 100644 --- a/core/services/streams/delegate_test.go +++ b/core/services/streams/delegate_test.go @@ -3,6 +3,7 @@ package streams import ( "testing" + "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/ocrcommon" @@ -35,12 +36,12 @@ func Test_Delegate(t *testing.T) { t.Run("ServicesForSpec", func(t *testing.T) { jb := job.Job{PipelineSpec: &pipeline.Spec{ID: 1}} t.Run("errors if job is missing streamID", func(t *testing.T) { - _, err := d.ServicesForSpec(jb) + _, err := d.ServicesForSpec(testutils.Context(t), jb) assert.EqualError(t, err, "streamID is required to be present for stream specs") }) jb.StreamID = ptr(uint32(42)) t.Run("returns services", func(t *testing.T) { - srvs, err := d.ServicesForSpec(jb) + srvs, err := d.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) assert.Len(t, srvs, 2) diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index ecabbc09c71..14ba341b1b6 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -1,6 +1,7 @@ package vrf import ( + "context" "fmt" "time" @@ -72,7 +73,7 @@ func (d *Delegate) BeforeJobDeleted(job.Job) {} func (d *Delegate) OnDeleteJob(job.Job, pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { if jb.VRFSpec == nil || jb.PipelineSpec == nil { return nil, errors.Errorf("vrf.Delegate expects a VRFSpec and PipelineSpec to be present, got %+v", jb) } @@ -128,7 +129,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { for _, task := range pl.Tasks { if _, ok := task.(*pipeline.VRFTaskV2Plus); ok { - if err2 := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { + if err2 := CheckFromAddressesExist(ctx, jb, d.ks.Eth()); err != nil { return nil, err2 } @@ -187,7 +188,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { }, nil } if _, ok := task.(*pipeline.VRFTaskV2); ok { - if err2 := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { + if err2 := CheckFromAddressesExist(ctx, jb, d.ks.Eth()); err != nil { return nil, err2 } @@ -269,9 +270,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { // CheckFromAddressesExist returns an error if and only if one of the addresses // in the VRF spec's fromAddresses field does not exist in the keystore. -func CheckFromAddressesExist(jb job.Job, gethks keystore.Eth) (err error) { +func CheckFromAddressesExist(ctx context.Context, jb job.Job, gethks keystore.Eth) (err error) { for _, a := range jb.VRFSpec.FromAddresses { - _, err2 := gethks.Get(a.Hex()) + _, err2 := gethks.Get(ctx, a.Hex()) err = multierr.Append(err, err2) } return diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 8ad88d7b73b..bbbb2d75dff 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -91,7 +91,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) require.NoError(t, ks.Unlock(testutils.Password)) - k, err2 := ks.Eth().Create(testutils.FixtureChainID) + k, err2 := ks.Eth().Create(testutils.Context(t), testutils.FixtureChainID) require.NoError(t, err2) submitter := k.Address require.NoError(t, err) @@ -167,7 +167,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { require.NoError(t, err) err = vuni.jrm.CreateJob(&jb) require.NoError(t, err) - vl, err := vd.ServicesForSpec(jb) + vl, err := vd.ServicesForSpec(testutils.Context(t), jb) require.NoError(t, err) require.Len(t, vl, 1) listener := vl[0].(*v1.Listener) @@ -565,7 +565,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { var fromAddresses []string for i := 0; i < 3; i++ { - k, err := ks.Eth().Create(big.NewInt(1337)) + k, err := ks.Eth().Create(testutils.Context(t), big.NewInt(1337)) assert.NoError(t, err) fromAddresses = append(fromAddresses, k.Address.Hex()) } @@ -581,7 +581,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { Toml()) assert.NoError(t, err) - assert.NoError(t, vrf.CheckFromAddressesExist(jb, ks.Eth())) + assert.NoError(t, vrf.CheckFromAddressesExist(testutils.Context(t), jb, ks.Eth())) }) t.Run("one of from addresses doesn't exist", func(t *testing.T) { @@ -593,7 +593,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { var fromAddresses []string for i := 0; i < 3; i++ { - k, err := ks.Eth().Create(big.NewInt(1337)) + k, err := ks.Eth().Create(testutils.Context(t), big.NewInt(1337)) assert.NoError(t, err) fromAddresses = append(fromAddresses, k.Address.Hex()) } @@ -611,7 +611,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { Toml()) assert.NoError(t, err) - assert.Error(t, vrf.CheckFromAddressesExist(jb, ks.Eth())) + assert.Error(t, vrf.CheckFromAddressesExist(testutils.Context(t), jb, ks.Eth())) }) } @@ -701,7 +701,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { require.NoError(t, err) err = vuni.jrm.CreateJob(&jb) require.NoError(t, err) - _, err = vd.ServicesForSpec(jb) + _, err = vd.ServicesForSpec(testutils.Context(t), jb) require.Error(t, err) require.Equal(t, "VRF Owner is not supported for VRF V2 Plus", err.Error()) } diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 5114015c008..18be6d8e408 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -1653,7 +1653,7 @@ func TestIntegrationVRFV2(t *testing.T) { carolContractAddress := uni.consumerContractAddresses[0] app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, key) - keys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + keys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) require.Zero(t, key.Cmp(keys[0])) @@ -2068,7 +2068,7 @@ func TestStartingCountsV1(t *testing.T) { assert.Equal(t, 0, len(counts)) err = ks.Unlock(testutils.Password) require.NoError(t, err) - k, err := ks.Eth().Create(testutils.SimulatedChainID) + k, err := ks.Eth().Create(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) b := time.Now() n1, n2, n3, n4 := evmtypes.Nonce(0), evmtypes.Nonce(1), evmtypes.Nonce(2), evmtypes.Nonce(3) diff --git a/core/services/vrf/v2/listener_v2_log_processor.go b/core/services/vrf/v2/listener_v2_log_processor.go index be9457d7cee..7f61dd4cf3e 100644 --- a/core/services/vrf/v2/listener_v2_log_processor.go +++ b/core/services/vrf/v2/listener_v2_log_processor.go @@ -387,7 +387,7 @@ func (lsn *listenerV2) processRequestsPerSubBatchHelper( "blockHash", p.req.req.Raw().BlockHash, ) fromAddresses := lsn.fromAddresses() - fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) + fromAddress, err := lsn.gethks.GetRoundRobinAddress(ctx, lsn.chainID, fromAddresses...) if err != nil { l.Errorw("Couldn't get next from address", "err", err) continue @@ -717,7 +717,7 @@ func (lsn *listenerV2) processRequestsPerSubHelper( "blockNumber", p.req.req.Raw().BlockNumber, "blockHash", p.req.req.Raw().BlockHash, ) - fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) + fromAddress, err := lsn.gethks.GetRoundRobinAddress(ctx, lsn.chainID, fromAddresses...) if err != nil { l.Errorw("Couldn't get next from address", "err", err) continue diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index d8bc0a6695b..465e3dcaca9 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -186,7 +186,7 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) chainID := testutils.SimulatedChainID - k, err := ks.Eth().Create(chainID) + k, err := ks.Eth().Create(testutils.Context(t), chainID) require.NoError(t, err) subID := new(big.Int).SetUint64(1) @@ -236,7 +236,7 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { require.Equal(t, "80000", start.String()) // One key's data should not affect other keys' data in the case of different subscribers. - k2, err := ks.Eth().Create(testutils.SimulatedChainID) + k2, err := ks.Eth().Create(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) anotherSubID := new(big.Int).SetUint64(3) @@ -268,7 +268,7 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) chainID := testutils.SimulatedChainID - k, err := ks.Eth().Create(chainID) + k, err := ks.Eth().Create(testutils.Context(t), chainID) require.NoError(t, err) subID := new(big.Int).SetUint64(1) @@ -319,7 +319,7 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) require.Equal(t, "80000", start.String()) // One key's data should not affect other keys' data in the case of different subscribers. - k2, err := ks.Eth().Create(testutils.SimulatedChainID) + k2, err := ks.Eth().Create(testutils.Context(t), testutils.SimulatedChainID) require.NoError(t, err) anotherSubID := new(big.Int).SetUint64(3) diff --git a/core/services/vrf/v2/reverted_txns.go b/core/services/vrf/v2/reverted_txns.go index 5aead146f5f..be20738a8f5 100644 --- a/core/services/vrf/v2/reverted_txns.go +++ b/core/services/vrf/v2/reverted_txns.go @@ -655,7 +655,7 @@ func (lsn *listenerV2) enqueueForceFulfillmentForRevertedTxn( reqCommitment := revertedTxn.Commitment fromAddresses := lsn.fromAddresses() - fromAddress, err := lsn.gethks.GetRoundRobinAddress(lsn.chainID, fromAddresses...) + fromAddress, err := lsn.gethks.GetRoundRobinAddress(ctx, lsn.chainID, fromAddresses...) if err != nil { return txmgr.Tx{}, errors.Wrap(err, "failed_to_get_vrf_listener_from_address") } diff --git a/core/services/vrf/vrfcommon/types.go b/core/services/vrf/vrfcommon/types.go index 175b362b5aa..06988633e8e 100644 --- a/core/services/vrf/vrfcommon/types.go +++ b/core/services/vrf/vrfcommon/types.go @@ -1,6 +1,7 @@ package vrfcommon import ( + "context" "math/big" "github.com/ethereum/go-ethereum/common" @@ -10,7 +11,7 @@ import ( ) type GethKeyStore interface { - GetRoundRobinAddress(chainID *big.Int, addresses ...common.Address) (common.Address, error) + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (common.Address, error) } //go:generate mockery --quiet --name Config --output ../mocks/ --case=underscore diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index 7e6aab0bb07..3211018d48d 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -76,7 +76,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) { func (d *Delegate) OnDeleteJob(jb job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.ServiceCtx, error) { service := &pseudoService{ spec: spec, webhookJobRunner: d.webhookJobRunner, diff --git a/core/services/webhook/delegate_test.go b/core/services/webhook/delegate_test.go index 24c501e7545..c020f641615 100644 --- a/core/services/webhook/delegate_test.go +++ b/core/services/webhook/delegate_test.go @@ -21,6 +21,7 @@ import ( ) func TestWebhookDelegate(t *testing.T) { + ctx := testutils.Context(t) var ( spec = &job.Job{ ID: 123, @@ -50,18 +51,18 @@ func TestWebhookDelegate(t *testing.T) { delegate = webhook.NewDelegate(runner, eiManager, logger.TestLogger(t)) ) - services, err := delegate.ServicesForSpec(*spec) + services, err := delegate.ServicesForSpec(ctx, *spec) require.NoError(t, err) require.Len(t, services, 1) service := services[0] // Should error before service is started - _, err = delegate.WebhookJobRunner().RunJob(testutils.Context(t), spec.ExternalJobID, requestBody, meta) + _, err = delegate.WebhookJobRunner().RunJob(ctx, spec.ExternalJobID, requestBody, meta) require.Error(t, err) require.Equal(t, webhook.ErrJobNotExists, errors.Cause(err)) // Should succeed after service is started upon a successful run - err = service.Start(testutils.Context(t)) + err = service.Start(ctx) require.NoError(t, err) runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything, mock.Anything). @@ -73,7 +74,7 @@ func TestWebhookDelegate(t *testing.T) { require.Equal(t, vars, run.Inputs.Val) }).Once() - runID, err := delegate.WebhookJobRunner().RunJob(testutils.Context(t), spec.ExternalJobID, requestBody, meta) + runID, err := delegate.WebhookJobRunner().RunJob(ctx, spec.ExternalJobID, requestBody, meta) require.NoError(t, err) require.Equal(t, int64(123), runID) @@ -83,13 +84,13 @@ func TestWebhookDelegate(t *testing.T) { runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything, mock.Anything). Return(false, expectedErr).Once() - _, err = delegate.WebhookJobRunner().RunJob(testutils.Context(t), spec.ExternalJobID, requestBody, meta) + _, err = delegate.WebhookJobRunner().RunJob(ctx, spec.ExternalJobID, requestBody, meta) require.Equal(t, expectedErr, errors.Cause(err)) // Should error after service is stopped err = service.Close() require.NoError(t, err) - _, err = delegate.WebhookJobRunner().RunJob(testutils.Context(t), spec.ExternalJobID, requestBody, meta) + _, err = delegate.WebhookJobRunner().RunJob(ctx, spec.ExternalJobID, requestBody, meta) require.Equal(t, webhook.ErrJobNotExists, errors.Cause(err)) } diff --git a/core/services/workflows/delegate.go b/core/services/workflows/delegate.go index 6faa0bacdb8..2951c2b4aa3 100644 --- a/core/services/workflows/delegate.go +++ b/core/services/workflows/delegate.go @@ -1,6 +1,7 @@ package workflows import ( + "context" "fmt" "github.com/google/uuid" @@ -34,7 +35,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(jb job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.ServiceCtx, error) { engine, err := NewEngine(d.logger, d.registry) if err != nil { return nil, err diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 339792fd06d..aa84dc29cc9 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/values" coreCap "github.com/smartcontractkit/chainlink/v2/core/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -66,7 +67,7 @@ func (m *mockTriggerCapability) UnregisterTrigger(ctx context.Context, req capab } func TestEngineWithHardcodedWorkflow(t *testing.T) { - ctx := context.Background() + ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) trigger := &mockTriggerCapability{ diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index 4e95bc3cb89..e53f30a925a 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -85,13 +85,13 @@ func (ekc *ETHKeysController) Index(c *gin.Context) { ethKeyStore := ekc.app.GetKeyStore().Eth() var keys []ethkey.KeyV2 var err error - keys, err = ethKeyStore.GetAll() + keys, err = ethKeyStore.GetAll(c.Request.Context()) if err != nil { err = errors.Errorf("error getting unlocked keys: %v", err) jsonAPIError(c, http.StatusInternalServerError, err) return } - states, err := ethKeyStore.GetStatesForKeys(keys) + states, err := ethKeyStore.GetStatesForKeys(c.Request.Context(), keys) if err != nil { err = errors.Errorf("error getting key states: %v", err) jsonAPIError(c, http.StatusInternalServerError, err) @@ -99,7 +99,7 @@ func (ekc *ETHKeysController) Index(c *gin.Context) { } var resources []presenters.ETHKeyResource for _, state := range states { - key, err := ethKeyStore.Get(state.Address.Hex()) + key, err := ethKeyStore.Get(c.Request.Context(), state.Address.Hex()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -136,13 +136,13 @@ func (ekc *ETHKeysController) Create(c *gin.Context) { return } - key, err := ethKeyStore.Create(chain.ID()) + key, err := ethKeyStore.Create(c.Request.Context(), chain.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return } - state, err := ethKeyStore.GetState(key.ID(), chain.ID()) + state, err := ethKeyStore.GetState(c.Request.Context(), key.ID(), chain.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -169,7 +169,7 @@ func (ekc *ETHKeysController) Delete(c *gin.Context) { return } - key, err := ethKeyStore.Get(keyID) + key, err := ethKeyStore.Get(c.Request.Context(), keyID) if err != nil { if errors.Is(err, keystore.ErrKeyNotFound) { jsonAPIError(c, http.StatusNotFound, err) @@ -179,13 +179,13 @@ func (ekc *ETHKeysController) Delete(c *gin.Context) { return } - state, err := ethKeyStore.GetStateForKey(key) + state, err := ethKeyStore.GetStateForKey(c.Request.Context(), key) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return } - _, err = ethKeyStore.Delete(keyID) + _, err = ethKeyStore.Delete(c.Request.Context(), keyID) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -217,13 +217,13 @@ func (ekc *ETHKeysController) Import(c *gin.Context) { return } - key, err := ethKeyStore.Import(bytes, oldPassword, chain.ID()) + key, err := ethKeyStore.Import(c.Request.Context(), bytes, oldPassword, chain.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return } - state, err := ethKeyStore.GetState(key.ID(), chain.ID()) + state, err := ethKeyStore.GetState(c.Request.Context(), key.ID(), chain.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -245,7 +245,7 @@ func (ekc *ETHKeysController) Export(c *gin.Context) { id := c.Param("address") newPassword := c.Query("newpassword") - bytes, err := ekc.app.GetKeyStore().Eth().Export(id, newPassword) + bytes, err := ekc.app.GetKeyStore().Eth().Export(c.Request.Context(), id, newPassword) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return @@ -312,9 +312,9 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { } if enabled { - err = kst.Enable(address, chain.ID()) + err = kst.Enable(c.Request.Context(), address, chain.ID()) } else { - err = kst.Disable(address, chain.ID()) + err = kst.Disable(c.Request.Context(), address, chain.ID()) } if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) @@ -322,13 +322,13 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { } } - key, err := kst.Get(keyID) + key, err := kst.Get(c.Request.Context(), keyID) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return } - state, err := kst.GetState(key.ID(), chain.ID()) + state, err := kst.GetState(c.Request.Context(), key.ID(), chain.ID()) if err != nil { jsonAPIError(c, http.StatusInternalServerError, err) return diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index e075b3196e1..545abefcd3e 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -175,7 +175,7 @@ func TestETHKeysController_Index_NotDev(t *testing.T) { defer cleanup() require.Equal(t, http.StatusOK, resp.StatusCode) - expectedKeys, err := app.KeyStore.Eth().GetAll() + expectedKeys, err := app.KeyStore.Eth().GetAll(testutils.Context(t)) require.NoError(t, err) var actualBalances []webpresenters.ETHKeyResource err = cltest.ParseJSONAPIResponse(t, resp, &actualBalances) diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index f574c885ff9..7d1e3ff5025 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -96,9 +96,9 @@ func TestResolver_ETHKeys(t *testing.T) { m := map[string]legacyevm.Chain{states[0].EVMChainID.String(): f.Mocks.chain} legacyEVMChains := legacyevm.NewLegacyChains(m, cfg.EVMConfigs()) - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) - f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(keys[0], nil) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.balM.On("GetEthBalance", address).Return(assets.NewEth(1)) @@ -158,9 +158,9 @@ func TestResolver_ETHKeys(t *testing.T) { } 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) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(keys[0], nil) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains f.Mocks.evmORM.PutChains(toml.EVMConfig{ChainID: &chainID}) f.Mocks.relayerChainInterops.Relayers = []loop.Relayer{ @@ -202,7 +202,7 @@ func TestResolver_ETHKeys(t *testing.T) { name: "generic error on GetAll()", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ethKs.On("GetAll").Return(nil, gError) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(nil, gError) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -221,8 +221,8 @@ func TestResolver_ETHKeys(t *testing.T) { name: "generic error on GetStatesForKeys()", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.ethKs.On("GetAll").Return(keys, nil) - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(nil, gError) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(nil, gError) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -251,9 +251,9 @@ func TestResolver_ETHKeys(t *testing.T) { }, } - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) - f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(ethkey.KeyV2{}, gError) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(ethkey.KeyV2{}, gError) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.App.On("GetKeyStore").Return(f.Mocks.keystore) }, @@ -283,9 +283,9 @@ func TestResolver_ETHKeys(t *testing.T) { }, } - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) - f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(ethkey.KeyV2{}, nil) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(ethkey.KeyV2{}, nil) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, gError) f.Mocks.relayerChainInterops.EVMChains = f.Mocks.legacyEVMChains @@ -316,9 +316,9 @@ func TestResolver_ETHKeys(t *testing.T) { chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) - f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(keys[0], nil) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.keystore.On("Eth").Return(f.Mocks.ethKs) f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), gError) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(f.Mocks.chain, nil) @@ -378,9 +378,9 @@ func TestResolver_ETHKeys(t *testing.T) { chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") - f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) - f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) - f.Mocks.ethKs.On("GetAll").Return(keys, nil) + f.Mocks.ethKs.On("GetStatesForKeys", mock.Anything, keys).Return(states, nil) + f.Mocks.ethKs.On("Get", mock.Anything, keys[0].Address.Hex()).Return(keys[0], nil) + f.Mocks.ethKs.On("GetAll", mock.Anything).Return(keys, nil) f.Mocks.ethClient.On("LINKBalance", mock.Anything, address, linkAddr).Return(commonassets.NewLinkFromJuels(12), nil) f.Mocks.chain.On("Client").Return(f.Mocks.ethClient) f.Mocks.chain.On("BalanceMonitor").Return(nil) diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index ccc9da2ab91..f9039fd17fc 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -417,12 +417,12 @@ func (r *Resolver) ETHKeys(ctx context.Context) (*ETHKeysPayloadResolver, error) ks := r.App.GetKeyStore().Eth() - keys, err := ks.GetAll() + keys, err := ks.GetAll(ctx) if err != nil { return nil, fmt.Errorf("error getting unlocked keys: %v", err) } - states, err := ks.GetStatesForKeys(keys) + states, err := ks.GetStatesForKeys(ctx, keys) if err != nil { return nil, fmt.Errorf("error getting key states: %v", err) } @@ -430,7 +430,7 @@ func (r *Resolver) ETHKeys(ctx context.Context) (*ETHKeysPayloadResolver, error) var ethKeys []ETHKey for _, state := range states { - k, err := ks.Get(state.Address.Hex()) + k, err := ks.Get(ctx, state.Address.Hex()) if err != nil { return nil, err } From e63bca68b5b3cdfd1ed8f20a22402deb60686f7e Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Tue, 27 Feb 2024 14:30:45 +0000 Subject: [PATCH 05/20] Stream fallback: error handler (#12173) (#12183) * Stream fallback: error handler (#12173) * Stop retry flow for error handling (log trigger) (#12026) * return timeout for retry interval * identify retryTimeout + placeholder for err handler * err codes * comments * added function and tests for handling err code * add checkErrorHandler (#12037) * Stop retry flow for error handling (conditional trigger) (#12032) * err codes for conditionals * unit tests for conditional * refactor streams error handler * fix mercury v0.2 request handling * fix mercury 0.3 DoRequest * fix tests * connect check error callback * add todo * add todo * improve comments * polish 0.2 * fix debug.go, refactor eth_call on checkCallback and checkErrorHandler, fix some minor comments (typo and test) * small fixes * calculate retry config for conditionals * rename to clarify function * cleanup pipeline execution errors * fix unit tests for v02_request.go * Fix bug in 0.3 request error code * add state assertion to single feed request tests * add test case for invalid response bytes * add tests for more retryable errors * add tests for retryable -> error conversion * polish 0.2 combining multiple feeds * add more tests for different combination of feed responses * remove unused fields * unit tests for v03 * fix mercury_test.go * minor polishing * thread control: added function that accept a context * use threadCtrl.GoCtx to ensure the timeout is applied with the provided context * added timeout for mercury requests (including retries) * fix lint * set timeout to 10s * use GoCtx within request clients * lint * add more 0.3 tests * set err code to timeout if ctx is done * Finalize stream error codes, polish requests to return consistent nil bytes upon error, use HttpToStreamsErrCode everywhere * add tests for checkErrorHanlder * treat timeout as non retryable error codes * allow empty feed request which returns error code * update test contract with a flag for checkErr result * generate wrappers for LogTriggeredStreamsLookup * handling empty performData case for err handler * test (wip) * fixing contract * waiting for err handler logs (wip) * update contract and generate wrappers * lint * use startBlock instead of 1 * add missing arg * check multiple responses: - server timeout - unauthorized - bad req - internal server err - not found * fix test * cleanup * set timeout in http client * Add timeout test for streams (#12170) * Add timeout test * fix DoRequest() to consider ctx (client v0.3) * make sure we timeout in time * align thread control test * hacky context timeout * trying to wait for timeout with child context * push hack * update * another fix * fix * use ctx background * add log * Use new ctx to implement timeout * fix test * add v0.2 test --------- Co-authored-by: amirylm * Empty Commit --------- Co-authored-by: Amir Y Co-authored-by: Lei * Empty Commit --------- Co-authored-by: Amir Y Co-authored-by: Lei --- .../v0.8/automation/dev/MercuryRegistry.sol | 8 + .../dev/MercuryRegistryBatchUpkeep.sol | 8 + .../StreamsLookupCompatibleInterface.sol | 13 + .../testhelpers/LogTriggeredStreamsLookup.sol | 17 +- .../src/v0.8/tests/StreamsLookupUpkeep.sol | 8 + .../tests/VerifiableLoadLogTriggerUpkeep.sol | 8 + .../VerifiableLoadStreamsLookupUpkeep.sol | 8 + .../log_triggered_streams_lookup_wrapper.go | 199 +++++++- .../streams_lookup_compatible_interface.go | 40 +- .../streams_lookup_upkeep_wrapper.go | 43 +- ...ifiable_load_log_trigger_upkeep_wrapper.go | 43 +- ...able_load_streams_lookup_upkeep_wrapper.go | 43 +- ...rapper-dependency-versions-do-not-edit.txt | 10 +- core/scripts/chaincli/handler/debug.go | 11 +- .../evmregistry/v21/encoding/interface.go | 62 ++- .../evmregistry/v21/mercury/mercury.go | 43 +- .../evmregistry/v21/mercury/mercury_test.go | 129 +++++ .../v21/mercury/streams/streams.go | 103 ++-- .../v21/mercury/streams/streams_test.go | 173 ++++++- .../evmregistry/v21/mercury/testutils.go | 72 +++ .../evmregistry/v21/mercury/v02/request.go | 166 +++++-- .../v21/mercury/v02/v02_request_test.go | 463 ++++++++++++++++-- .../evmregistry/v21/mercury/v03/request.go | 161 ++++-- .../v21/mercury/v03/v03_request_test.go | 392 ++++++++++++++- .../v21/registry_check_pipeline.go | 2 +- .../plugins/ocr2keeper/integration_21_test.go | 152 +++++- .../plugins/ocr2keeper/integration_test.go | 83 +--- core/utils/thread_control.go | 13 + core/utils/thread_control_test.go | 28 ++ .../contracts/contract_deployer.go | 2 +- sonar-project.properties | 3 +- 31 files changed, 2179 insertions(+), 327 deletions(-) create mode 100644 core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol index 6a5dafc196d..c49543b3e7c 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol @@ -144,6 +144,14 @@ contract MercuryRegistry is ConfirmedOwner, AutomationCompatibleInterface, Strea return (filteredValues.length > 0, performData); } + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (false, new bytes(0)); + } + // Use deviated off-chain values to update on-chain state. function performUpkeep(bytes calldata performData) external override { (bytes[] memory values /* bytes memory lookupData */, ) = abi.decode(performData, (bytes[], bytes)); diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol index 8fa32c8a68e..7005ca4812d 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol @@ -61,6 +61,14 @@ contract MercuryRegistryBatchUpkeep is ConfirmedOwner, AutomationCompatibleInter return i_registry.checkCallback(values, lookupData); } + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (false, new bytes(0)); + } + // Use the master registry to update state. function performUpkeep(bytes calldata performData) external override { i_registry.performUpkeep(performData); diff --git a/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol b/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol index cf8526a4651..b6ab3123f87 100644 --- a/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol +++ b/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol @@ -17,4 +17,17 @@ interface StreamsLookupCompatibleInterface { bytes[] memory values, bytes memory extraData ) external view returns (bool upkeepNeeded, bytes memory performData); + + /** + * @notice this is a new, optional function in streams lookup. It is meant to surface streams lookup errors. + * @param errCode an uint value that represents the streams lookup error code. + * @param extraData context data from streams lookup process. + * @return upkeepNeeded boolean to indicate whether the keeper should call performUpkeep or not. + * @return performData bytes that the keeper should call performUpkeep with, if + * upkeep is needed. If you would like to encode data to decode later, try `abi.encode`. + */ + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view returns (bool upkeepNeeded, bytes memory performData); } diff --git a/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol index 5bdea03139c..d0b89b37b31 100644 --- a/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol +++ b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol @@ -26,6 +26,7 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt bytes verified ); event LimitOrderExecuted(uint256 indexed orderId, uint256 indexed amount, address indexed exchange); // keccak(LimitOrderExecuted(uint256,uint256,address)) => 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd + event IgnoringErrorHandlerData(); ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); IVerifierProxy internal constant VERIFIER = IVerifierProxy(0x09DFf56A4fF44e0f4436260A04F5CFa65636A481); @@ -42,10 +43,12 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt string public feedParamKey = "feedIdHex"; string public timeParamKey = "blockNumber"; uint256 public counter; + bool public checkErrReturnBool; - constructor(bool _useArbitrumBlockNum, bool _verify) { + constructor(bool _useArbitrumBlockNum, bool _verify, bool _checkErrReturnBool) { useArbitrumBlockNum = _useArbitrumBlockNum; verify = _verify; + checkErrReturnBool = _checkErrReturnBool; counter = 0; } @@ -94,6 +97,10 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt } function performUpkeep(bytes calldata performData) external override { + if (performData.length == 0) { + emit IgnoringErrorHandlerData(); + return; + } (bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes)); (uint256 orderId, uint256 amount, address exchange, bytes32 logTopic0) = abi.decode( extraData, @@ -130,6 +137,14 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt return (true, performData); } + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (checkErrReturnBool, new bytes(0)); + } + function getBlockNumber() internal view returns (uint256) { if (useArbitrumBlockNum) { return ARB_SYS.arbBlockNumber(); diff --git a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol index 69729a189e2..dec93d5b1f7 100644 --- a/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/StreamsLookupUpkeep.sol @@ -88,6 +88,14 @@ contract StreamsLookupUpkeep is AutomationCompatibleInterface, StreamsLookupComp return (callbackReturnBool, performData); } + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (false, new bytes(0)); + } + function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) { if (!eligible()) { return (false, data); diff --git a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol index 45630fcadc6..39b95bb0ae5 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadLogTriggerUpkeep.sol @@ -116,4 +116,12 @@ contract VerifiableLoadLogTriggerUpkeep is VerifiableLoadBase, StreamsLookupComp bytes memory performData = abi.encode(values, extraData); return (true, performData); } + + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (false, new bytes(0)); + } } diff --git a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol index 209c60ca974..c74aec1a790 100644 --- a/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol +++ b/contracts/src/v0.8/tests/VerifiableLoadStreamsLookupUpkeep.sol @@ -16,6 +16,14 @@ contract VerifiableLoadStreamsLookupUpkeep is VerifiableLoadBase, StreamsLookupC return (true, performData); } + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + // dummy function with default values + return (false, new bytes(0)); + } + function checkUpkeep(bytes calldata checkData) external returns (bool, bytes memory) { uint256 startGas = gasleft(); uint256 upkeepId = abi.decode(checkData, (uint256)); diff --git a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go index ccd5aea2c37..766f564ba71 100644 --- a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go +++ b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go @@ -42,15 +42,15 @@ type Log struct { } var LogTriggeredStreamsLookupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_useArbitrumBlockNum\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"}],\"name\":\"LimitOrderExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blob\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verified\",\"type\":\"bytes\"}],\"name\":\"PerformingLogTriggerUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"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\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParam\",\"type\":\"string\"}],\"name\":\"setFeedParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"newFeeds\",\"type\":\"string[]\"}],\"name\":\"setFeedsHex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"timeParam\",\"type\":\"string\"}],\"name\":\"setTimeParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"start\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x610120604052604260a08181526080918291906200179660c03990526200002a9060019081620000e8565b506040805180820190915260098152680cccacac892c890caf60bb1b60208201526002906200005a908262000264565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526003906200008c908262000264565b503480156200009a57600080fd5b50604051620017d8380380620017d8833981016040819052620000bd9162000346565b6000805461ffff191692151561ff00191692909217610100911515919091021781556004556200037e565b82805482825590600052602060002090810192821562000133579160200282015b8281111562000133578251829062000122908262000264565b509160200191906001019062000109565b506200014192915062000145565b5090565b80821115620001415760006200015c828262000166565b5060010162000145565b5080546200017490620001d5565b6000825580601f1062000185575050565b601f016020900490600052602060002090810190620001a59190620001a8565b50565b5b80821115620001415760008155600101620001a9565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ea57607f821691505b6020821081036200020b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200025f57600081815260208120601f850160051c810160208610156200023a5750805b601f850160051c820191505b818110156200025b5782815560010162000246565b5050505b505050565b81516001600160401b03811115620002805762000280620001bf565b6200029881620002918454620001d5565b8462000211565b602080601f831160018114620002d05760008415620002b75750858301515b600019600386901b1c1916600185901b1785556200025b565b600085815260208120601f198616915b828110156200030157888601518255948401946001909101908401620002e0565b5085821015620003205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b805180151581146200034157600080fd5b919050565b600080604083850312156200035a57600080fd5b620003658362000330565b9150620003756020840162000330565b90509250929050565b611408806200038e6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063642f6cef1161008c578063afb28d1f11610066578063afb28d1f146101c3578063be9a6555146101cb578063c98f10b0146101d3578063fc735e99146101db57600080fd5b8063642f6cef146101735780639525d574146101905780639d6f1cc7146101a357600080fd5b80634b56a42e116100bd5780634b56a42e14610136578063601d5a711461014957806361bc221a1461015c57600080fd5b806305e25131146100e457806340691db4146100f95780634585e33b14610123575b600080fd5b6100f76100f2366004610ac8565b6101ed565b005b61010c610107366004610b79565b610204565b60405161011a929190610c54565b60405180910390f35b6100f7610131366004610c77565b6104da565b61010c610144366004610ce9565b6106d8565b6100f7610157366004610da6565b61072e565b61016560045481565b60405190815260200161011a565b6000546101809060ff1681565b604051901515815260200161011a565b6100f761019e366004610da6565b61073a565b6101b66101b1366004610ddb565b610746565b60405161011a9190610df4565b6101b66107f2565b6100f76107ff565b6101b6610832565b60005461018090610100900460ff1681565b80516102009060019060208401906108c5565b5050565b60006060600061021261083f565b90507fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd61024260c0870187610e0e565b600081811061025357610253610e76565b905060200201350361045257600061026e60c0870187610e0e565b600181811061027f5761027f610e76565b9050602002013560405160200161029891815260200190565b60405160208183030381529060405290506000818060200190518101906102bf9190610ea5565b905060006102d060c0890189610e0e565b60028181106102e1576102e1610e76565b905060200201356040516020016102fa91815260200190565b60405160208183030381529060405290506000818060200190518101906103219190610ea5565b9050600061033260c08b018b610e0e565b600381811061034357610343610e76565b9050602002013560405160200161035c91815260200190565b60405160208183030381529060405290506000818060200190518101906103839190610ee7565b604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff821660608201527fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd60808201529091506002906001906003908a9060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526104499594939291600401610ff0565b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f636f756c64206e6f742066696e64206d61746368696e67206576656e7420736960448201527f67000000000000000000000000000000000000000000000000000000000000006064820152608401610449565b6000806104e983850185610ce9565b915091506000806000808480602001905181019061050791906110b3565b6040805160208101909152600080825254949850929650909450925090610100900460ff1615610600577309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe8860008151811061057457610574610e76565b60200260200101516040518263ffffffff1660e01b81526004016105989190610df4565b6000604051808303816000875af11580156105b7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105fd91908101906110f0565b90505b60045461060e906001611167565b6004557f2e00161baa7e3ee28260d12a08ade832b4160748111950f092fc0b921ac6a933820161066a576040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a45b327f299a03817e683a32b21e29e3ae3c31f1c9c773f7d532836d116b62a9281fbc9d86868661069761083f565b8c6000815181106106aa576106aa610e76565b6020026020010151876040516106c5969594939291906111a7565b60405180910390a2505050505050505050565b60006060600084846040516020016106f1929190611207565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052600193509150505b9250929050565b600361020082826112e1565b600261020082826112e1565b6001818154811061075657600080fd5b90600052602060002001600091509050805461077190610f02565b80601f016020809104026020016040519081016040528092919081815260200182805461079d90610f02565b80156107ea5780601f106107bf576101008083540402835291602001916107ea565b820191906000526020600020905b8154815290600101906020018083116107cd57829003601f168201915b505050505081565b6002805461077190610f02565b6040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a4565b6003805461077190610f02565b6000805460ff16156108c057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bb9190610ea5565b905090565b504390565b82805482825590600052602060002090810192821561090b579160200282015b8281111561090b57825182906108fb90826112e1565b50916020019190600101906108e5565b5061091792915061091b565b5090565b8082111561091757600061092f8282610938565b5060010161091b565b50805461094490610f02565b6000825580601f10610954575050565b601f0160209004906000526020600020908101906109729190610975565b50565b5b808211156109175760008155600101610976565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a0057610a0061098a565b604052919050565b600067ffffffffffffffff821115610a2257610a2261098a565b5060051b60200190565b600067ffffffffffffffff821115610a4657610a4661098a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610a8357600080fd5b8135610a96610a9182610a2c565b6109b9565b818152846020838601011115610aab57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020808385031215610adb57600080fd5b823567ffffffffffffffff80821115610af357600080fd5b818501915085601f830112610b0757600080fd5b8135610b15610a9182610a08565b81815260059190911b83018401908481019088831115610b3457600080fd5b8585015b83811015610b6c57803585811115610b505760008081fd5b610b5e8b89838a0101610a72565b845250918601918601610b38565b5098975050505050505050565b60008060408385031215610b8c57600080fd5b823567ffffffffffffffff80821115610ba457600080fd5b908401906101008287031215610bb957600080fd5b90925060208401359080821115610bcf57600080fd5b50610bdc85828601610a72565b9150509250929050565b60005b83811015610c01578181015183820152602001610be9565b50506000910152565b60008151808452610c22816020860160208601610be6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000610c6f6040830184610c0a565b949350505050565b60008060208385031215610c8a57600080fd5b823567ffffffffffffffff80821115610ca257600080fd5b818501915085601f830112610cb657600080fd5b813581811115610cc557600080fd5b866020828501011115610cd757600080fd5b60209290920196919550909350505050565b60008060408385031215610cfc57600080fd5b823567ffffffffffffffff80821115610d1457600080fd5b818501915085601f830112610d2857600080fd5b81356020610d38610a9183610a08565b82815260059290921b84018101918181019089841115610d5757600080fd5b8286015b84811015610d8f57803586811115610d735760008081fd5b610d818c86838b0101610a72565b845250918301918301610d5b565b5096505086013592505080821115610bcf57600080fd5b600060208284031215610db857600080fd5b813567ffffffffffffffff811115610dcf57600080fd5b610c6f84828501610a72565b600060208284031215610ded57600080fd5b5035919050565b602081526000610e076020830184610c0a565b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e4357600080fd5b83018035915067ffffffffffffffff821115610e5e57600080fd5b6020019150600581901b360382131561072757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610eb757600080fd5b5051919050565b805173ffffffffffffffffffffffffffffffffffffffff81168114610ee257600080fd5b919050565b600060208284031215610ef957600080fd5b610e0782610ebe565b600181811c90821680610f1657607f821691505b602082108103610f4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008154610f6281610f02565b808552602060018381168015610f7f5760018114610fb757610fe5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550610fe5565b866000528260002060005b85811015610fdd5781548a8201860152908301908401610fc2565b890184019650505b505050505092915050565b60a08152600061100360a0830188610f55565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015611075577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526110638383610f55565b9486019492506001918201910161102a565b50508681036040880152611089818b610f55565b94505050505084606084015282810360808401526110a78185610c0a565b98975050505050505050565b600080600080608085870312156110c957600080fd5b84519350602085015192506110e060408601610ebe565b6060959095015193969295505050565b60006020828403121561110257600080fd5b815167ffffffffffffffff81111561111957600080fd5b8201601f8101841361112a57600080fd5b8051611138610a9182610a2c565b81815285602083850101111561114d57600080fd5b61115e826020830160208601610be6565b95945050505050565b808201808211156111a1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b86815285602082015273ffffffffffffffffffffffffffffffffffffffff8516604082015283606082015260c0608082015260006111e860c0830185610c0a565b82810360a08401526111fa8185610c0a565b9998505050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561127c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261126a868351610c0a565b95509382019390820190600101611230565b50508584038187015250505061115e8185610c0a565b601f8211156112dc57600081815260208120601f850160051c810160208610156112b95750805b601f850160051c820191505b818110156112d8578281556001016112c5565b5050505b505050565b815167ffffffffffffffff8111156112fb576112fb61098a565b61130f816113098454610f02565b84611292565b602080601f831160018114611362576000841561132c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556112d8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156113af57888601518255948401946001909101908401611390565b50858210156113eb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_useArbitrumBlockNum\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_checkErrReturnBool\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"IgnoringErrorHandlerData\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"}],\"name\":\"LimitOrderExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blob\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verified\",\"type\":\"bytes\"}],\"name\":\"PerformingLogTriggerUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkErrReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"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\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParam\",\"type\":\"string\"}],\"name\":\"setFeedParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"newFeeds\",\"type\":\"string[]\"}],\"name\":\"setFeedsHex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"timeParam\",\"type\":\"string\"}],\"name\":\"setTimeParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"start\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x610120604052604260a08181526080918291906200188360c03990526200002a9060019081620000fc565b506040805180820190915260098152680cccacac892c890caf60bb1b60208201526002906200005a908262000278565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526003906200008c908262000278565b503480156200009a57600080fd5b50604051620018c5380380620018c5833981016040819052620000bd916200035a565b6000805461ffff191693151561ff00191693909317610100921515929092029190911782556005805460ff1916911515919091179055600455620003a4565b82805482825590600052602060002090810192821562000147579160200282015b8281111562000147578251829062000136908262000278565b50916020019190600101906200011d565b506200015592915062000159565b5090565b80821115620001555760006200017082826200017a565b5060010162000159565b5080546200018890620001e9565b6000825580601f1062000199575050565b601f016020900490600052602060002090810190620001b99190620001bc565b50565b5b80821115620001555760008155600101620001bd565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001fe57607f821691505b6020821081036200021f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200027357600081815260208120601f850160051c810160208610156200024e5750805b601f850160051c820191505b818110156200026f578281556001016200025a565b5050505b505050565b81516001600160401b03811115620002945762000294620001d3565b620002ac81620002a58454620001e9565b8462000225565b602080601f831160018114620002e45760008415620002cb5750858301515b600019600386901b1c1916600185901b1785556200026f565b600085815260208120601f198616915b828110156200031557888601518255948401946001909101908401620002f4565b5085821015620003345787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b805180151581146200035557600080fd5b919050565b6000806000606084860312156200037057600080fd5b6200037b8462000344565b92506200038b6020850162000344565b91506200039b6040850162000344565b90509250925092565b6114cf80620003b46000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806361bc221a11610097578063afb28d1f11610066578063afb28d1f146101f9578063be9a655514610201578063c98f10b014610209578063fc735e991461021157600080fd5b806361bc221a146101a2578063642f6cef146101b95780639525d574146101c65780639d6f1cc7146101d957600080fd5b806340691db4116100d357806340691db4146101565780634585e33b146101695780634b56a42e1461017c578063601d5a711461018f57600080fd5b806305e25131146100fa5780630fb172fb1461010f5780631d1477b714610139575b600080fd5b61010d610108366004610b52565b610223565b005b61012261011d366004610c03565b61023a565b604051610130929190610cb8565b60405180910390f35b6005546101469060ff1681565b6040519015158152602001610130565b610122610164366004610cdb565b61025a565b61010d610177366004610d3e565b610530565b61012261018a366004610db0565b610764565b61010d61019d366004610e6d565b6107b8565b6101ab60045481565b604051908152602001610130565b6000546101469060ff1681565b61010d6101d4366004610e6d565b6107c4565b6101ec6101e7366004610ea2565b6107d0565b6040516101309190610ebb565b6101ec61087c565b61010d610889565b6101ec6108bc565b60005461014690610100900460ff1681565b805161023690600190602084019061094f565b5050565b60055460408051600081526020810190915260ff909116905b9250929050565b6000606060006102686108c9565b90507fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd61029860c0870187610ed5565b60008181106102a9576102a9610f3d565b90506020020135036104a85760006102c460c0870187610ed5565b60018181106102d5576102d5610f3d565b905060200201356040516020016102ee91815260200190565b60405160208183030381529060405290506000818060200190518101906103159190610f6c565b9050600061032660c0890189610ed5565b600281811061033757610337610f3d565b9050602002013560405160200161035091815260200190565b60405160208183030381529060405290506000818060200190518101906103779190610f6c565b9050600061038860c08b018b610ed5565b600381811061039957610399610f3d565b905060200201356040516020016103b291815260200190565b60405160208183030381529060405290506000818060200190518101906103d99190610fae565b604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff821660608201527fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd60808201529091506002906001906003908a9060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a200000000000000000000000000000000000000000000000000000000825261049f95949392916004016110b7565b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f636f756c64206e6f742066696e64206d61746368696e67206576656e7420736960448201527f6700000000000000000000000000000000000000000000000000000000000000606482015260840161049f565b6000819003610566576040517f4f11cf8b97a2a25842c70eb74501fde8edea68ca2884190c1e3d26c8850441fe90600090a15050565b60008061057583850185610db0565b9150915060008060008084806020019051810190610593919061117a565b6040805160208101909152600080825254949850929650909450925090610100900460ff161561068c577309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe8860008151811061060057610600610f3d565b60200260200101516040518263ffffffff1660e01b81526004016106249190610ebb565b6000604051808303816000875af1158015610643573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261068991908101906111b7565b90505b60045461069a90600161122e565b6004557f2e00161baa7e3ee28260d12a08ade832b4160748111950f092fc0b921ac6a93382016106f6576040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a45b327f299a03817e683a32b21e29e3ae3c31f1c9c773f7d532836d116b62a9281fbc9d8686866107236108c9565b8c60008151811061073657610736610f3d565b6020026020010151876040516107519695949392919061126e565b60405180910390a2505050505050505050565b600060606000848460405160200161077d9291906112ce565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b600361023682826113a8565b600261023682826113a8565b600181815481106107e057600080fd5b9060005260206000200160009150905080546107fb90610fc9565b80601f016020809104026020016040519081016040528092919081815260200182805461082790610fc9565b80156108745780601f1061084957610100808354040283529160200191610874565b820191906000526020600020905b81548152906001019060200180831161085757829003601f168201915b505050505081565b600280546107fb90610fc9565b6040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a4565b600380546107fb90610fc9565b6000805460ff161561094a57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610921573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109459190610f6c565b905090565b504390565b828054828255906000526020600020908101928215610995579160200282015b82811115610995578251829061098590826113a8565b509160200191906001019061096f565b506109a19291506109a5565b5090565b808211156109a15760006109b982826109c2565b506001016109a5565b5080546109ce90610fc9565b6000825580601f106109de575050565b601f0160209004906000526020600020908101906109fc91906109ff565b50565b5b808211156109a15760008155600101610a00565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a8a57610a8a610a14565b604052919050565b600067ffffffffffffffff821115610aac57610aac610a14565b5060051b60200190565b600067ffffffffffffffff821115610ad057610ad0610a14565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610b0d57600080fd5b8135610b20610b1b82610ab6565b610a43565b818152846020838601011115610b3557600080fd5b816020850160208301376000918101602001919091529392505050565b60006020808385031215610b6557600080fd5b823567ffffffffffffffff80821115610b7d57600080fd5b818501915085601f830112610b9157600080fd5b8135610b9f610b1b82610a92565b81815260059190911b83018401908481019088831115610bbe57600080fd5b8585015b83811015610bf657803585811115610bda5760008081fd5b610be88b89838a0101610afc565b845250918601918601610bc2565b5098975050505050505050565b60008060408385031215610c1657600080fd5b82359150602083013567ffffffffffffffff811115610c3457600080fd5b610c4085828601610afc565b9150509250929050565b60005b83811015610c65578181015183820152602001610c4d565b50506000910152565b60008151808452610c86816020860160208601610c4a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000610cd36040830184610c6e565b949350505050565b60008060408385031215610cee57600080fd5b823567ffffffffffffffff80821115610d0657600080fd5b908401906101008287031215610d1b57600080fd5b90925060208401359080821115610d3157600080fd5b50610c4085828601610afc565b60008060208385031215610d5157600080fd5b823567ffffffffffffffff80821115610d6957600080fd5b818501915085601f830112610d7d57600080fd5b813581811115610d8c57600080fd5b866020828501011115610d9e57600080fd5b60209290920196919550909350505050565b60008060408385031215610dc357600080fd5b823567ffffffffffffffff80821115610ddb57600080fd5b818501915085601f830112610def57600080fd5b81356020610dff610b1b83610a92565b82815260059290921b84018101918181019089841115610e1e57600080fd5b8286015b84811015610e5657803586811115610e3a5760008081fd5b610e488c86838b0101610afc565b845250918301918301610e22565b5096505086013592505080821115610d3157600080fd5b600060208284031215610e7f57600080fd5b813567ffffffffffffffff811115610e9657600080fd5b610cd384828501610afc565b600060208284031215610eb457600080fd5b5035919050565b602081526000610ece6020830184610c6e565b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610f0a57600080fd5b83018035915067ffffffffffffffff821115610f2557600080fd5b6020019150600581901b360382131561025357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610f7e57600080fd5b5051919050565b805173ffffffffffffffffffffffffffffffffffffffff81168114610fa957600080fd5b919050565b600060208284031215610fc057600080fd5b610ece82610f85565b600181811c90821680610fdd57607f821691505b602082108103611016577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000815461102981610fc9565b808552602060018381168015611046576001811461107e576110ac565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506110ac565b866000528260002060005b858110156110a45781548a8201860152908301908401611089565b890184019650505b505050505092915050565b60a0815260006110ca60a083018861101c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b8381101561113c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261112a838361101c565b948601949250600191820191016110f1565b50508681036040880152611150818b61101c565b945050505050846060840152828103608084015261116e8185610c6e565b98975050505050505050565b6000806000806080858703121561119057600080fd5b84519350602085015192506111a760408601610f85565b6060959095015193969295505050565b6000602082840312156111c957600080fd5b815167ffffffffffffffff8111156111e057600080fd5b8201601f810184136111f157600080fd5b80516111ff610b1b82610ab6565b81815285602083850101111561121457600080fd5b611225826020830160208601610c4a565b95945050505050565b80820180821115611268577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b86815285602082015273ffffffffffffffffffffffffffffffffffffffff8516604082015283606082015260c0608082015260006112af60c0830185610c6e565b82810360a08401526112c18185610c6e565b9998505050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611343577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611331868351610c6e565b955093820193908201906001016112f7565b5050858403818701525050506112258185610c6e565b601f8211156113a357600081815260208120601f850160051c810160208610156113805750805b601f850160051c820191505b8181101561139f5782815560010161138c565b5050505b505050565b815167ffffffffffffffff8111156113c2576113c2610a14565b6113d6816113d08454610fc9565b84611359565b602080601f83116001811461142957600084156113f35750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561139f565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561147657888601518255948401946001909101908401611457565b50858210156114b257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var LogTriggeredStreamsLookupABI = LogTriggeredStreamsLookupMetaData.ABI var LogTriggeredStreamsLookupBin = LogTriggeredStreamsLookupMetaData.Bin -func DeployLogTriggeredStreamsLookup(auth *bind.TransactOpts, backend bind.ContractBackend, _useArbitrumBlockNum bool, _verify bool) (common.Address, *types.Transaction, *LogTriggeredStreamsLookup, error) { +func DeployLogTriggeredStreamsLookup(auth *bind.TransactOpts, backend bind.ContractBackend, _useArbitrumBlockNum bool, _verify bool, _checkErrReturnBool bool) (common.Address, *types.Transaction, *LogTriggeredStreamsLookup, error) { parsed, err := LogTriggeredStreamsLookupMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -59,7 +59,7 @@ func DeployLogTriggeredStreamsLookup(auth *bind.TransactOpts, backend bind.Contr return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LogTriggeredStreamsLookupBin), backend, _useArbitrumBlockNum, _verify) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LogTriggeredStreamsLookupBin), backend, _useArbitrumBlockNum, _verify, _checkErrReturnBool) if err != nil { return common.Address{}, nil, nil, err } @@ -205,6 +205,58 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCallerSession) CheckC return _LogTriggeredStreamsLookup.Contract.CheckCallback(&_LogTriggeredStreamsLookup.CallOpts, values, extraData) } +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCaller) CheckErrReturnBool(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _LogTriggeredStreamsLookup.contract.Call(opts, &out, "checkErrReturnBool") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupSession) CheckErrReturnBool() (bool, error) { + return _LogTriggeredStreamsLookup.Contract.CheckErrReturnBool(&_LogTriggeredStreamsLookup.CallOpts) +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCallerSession) CheckErrReturnBool() (bool, error) { + return _LogTriggeredStreamsLookup.Contract.CheckErrReturnBool(&_LogTriggeredStreamsLookup.CallOpts) +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _LogTriggeredStreamsLookup.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _LogTriggeredStreamsLookup.Contract.CheckErrorHandler(&_LogTriggeredStreamsLookup.CallOpts, errCode, extraData) +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _LogTriggeredStreamsLookup.Contract.CheckErrorHandler(&_LogTriggeredStreamsLookup.CallOpts, errCode, extraData) +} + func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _LogTriggeredStreamsLookup.contract.Call(opts, &out, "counter") @@ -409,6 +461,122 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupTransactorSession) St return _LogTriggeredStreamsLookup.Contract.Start(&_LogTriggeredStreamsLookup.TransactOpts) } +type LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator struct { + Event *LogTriggeredStreamsLookupIgnoringErrorHandlerData + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LogTriggeredStreamsLookupIgnoringErrorHandlerData) + 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(LogTriggeredStreamsLookupIgnoringErrorHandlerData) + 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 *LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator) Error() error { + return it.fail +} + +func (it *LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LogTriggeredStreamsLookupIgnoringErrorHandlerData struct { + Raw types.Log +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) FilterIgnoringErrorHandlerData(opts *bind.FilterOpts) (*LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator, error) { + + logs, sub, err := _LogTriggeredStreamsLookup.contract.FilterLogs(opts, "IgnoringErrorHandlerData") + if err != nil { + return nil, err + } + return &LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator{contract: _LogTriggeredStreamsLookup.contract, event: "IgnoringErrorHandlerData", logs: logs, sub: sub}, nil +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) WatchIgnoringErrorHandlerData(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupIgnoringErrorHandlerData) (event.Subscription, error) { + + logs, sub, err := _LogTriggeredStreamsLookup.contract.WatchLogs(opts, "IgnoringErrorHandlerData") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LogTriggeredStreamsLookupIgnoringErrorHandlerData) + if err := _LogTriggeredStreamsLookup.contract.UnpackLog(event, "IgnoringErrorHandlerData", 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 (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) ParseIgnoringErrorHandlerData(log types.Log) (*LogTriggeredStreamsLookupIgnoringErrorHandlerData, error) { + event := new(LogTriggeredStreamsLookupIgnoringErrorHandlerData) + if err := _LogTriggeredStreamsLookup.contract.UnpackLog(event, "IgnoringErrorHandlerData", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type LogTriggeredStreamsLookupLimitOrderExecutedIterator struct { Event *LogTriggeredStreamsLookupLimitOrderExecuted @@ -687,8 +855,15 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) ParsePerfor return event, nil } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} + func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { + case _LogTriggeredStreamsLookup.abi.Events["IgnoringErrorHandlerData"].ID: + return _LogTriggeredStreamsLookup.ParseIgnoringErrorHandlerData(log) case _LogTriggeredStreamsLookup.abi.Events["LimitOrderExecuted"].ID: return _LogTriggeredStreamsLookup.ParseLimitOrderExecuted(log) case _LogTriggeredStreamsLookup.abi.Events["PerformingLogTriggerUpkeep"].ID: @@ -699,6 +874,10 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) ParseLog(log types. } } +func (LogTriggeredStreamsLookupIgnoringErrorHandlerData) Topic() common.Hash { + return common.HexToHash("0x4f11cf8b97a2a25842c70eb74501fde8edea68ca2884190c1e3d26c8850441fe") +} + func (LogTriggeredStreamsLookupLimitOrderExecuted) Topic() common.Hash { return common.HexToHash("0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd") } @@ -714,6 +893,12 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) Address() common.Ad type LogTriggeredStreamsLookupInterface interface { CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + CheckErrReturnBool(opts *bind.CallOpts) (bool, error) + + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + Counter(opts *bind.CallOpts) (*big.Int, error) FeedParamKey(opts *bind.CallOpts) (string, error) @@ -738,6 +923,12 @@ type LogTriggeredStreamsLookupInterface interface { Start(opts *bind.TransactOpts) (*types.Transaction, error) + FilterIgnoringErrorHandlerData(opts *bind.FilterOpts) (*LogTriggeredStreamsLookupIgnoringErrorHandlerDataIterator, error) + + WatchIgnoringErrorHandlerData(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupIgnoringErrorHandlerData) (event.Subscription, error) + + ParseIgnoringErrorHandlerData(log types.Log) (*LogTriggeredStreamsLookupIgnoringErrorHandlerData, error) + FilterLimitOrderExecuted(opts *bind.FilterOpts, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (*LogTriggeredStreamsLookupLimitOrderExecutedIterator, error) WatchLimitOrderExecuted(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupLimitOrderExecuted, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/streams_lookup_compatible_interface/streams_lookup_compatible_interface.go b/core/gethwrappers/generated/streams_lookup_compatible_interface/streams_lookup_compatible_interface.go index 41155618774..4d6d01c9e50 100644 --- a/core/gethwrappers/generated/streams_lookup_compatible_interface/streams_lookup_compatible_interface.go +++ b/core/gethwrappers/generated/streams_lookup_compatible_interface/streams_lookup_compatible_interface.go @@ -29,7 +29,7 @@ var ( ) var StreamsLookupCompatibleInterfaceMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"inputs\":[{\"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\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"inputs\":[{\"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\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } var StreamsLookupCompatibleInterfaceABI = StreamsLookupCompatibleInterfaceMetaData.ABI @@ -180,10 +180,44 @@ func (_StreamsLookupCompatibleInterface *StreamsLookupCompatibleInterfaceCallerS return _StreamsLookupCompatibleInterface.Contract.CheckCallback(&_StreamsLookupCompatibleInterface.CallOpts, values, extraData) } +func (_StreamsLookupCompatibleInterface *StreamsLookupCompatibleInterfaceCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _StreamsLookupCompatibleInterface.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_StreamsLookupCompatibleInterface *StreamsLookupCompatibleInterfaceSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _StreamsLookupCompatibleInterface.Contract.CheckErrorHandler(&_StreamsLookupCompatibleInterface.CallOpts, errCode, extraData) +} + +func (_StreamsLookupCompatibleInterface *StreamsLookupCompatibleInterfaceCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _StreamsLookupCompatibleInterface.Contract.CheckErrorHandler(&_StreamsLookupCompatibleInterface.CallOpts, errCode, extraData) +} + type CheckCallback struct { UpkeepNeeded bool PerformData []byte } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} func (_StreamsLookupCompatibleInterface *StreamsLookupCompatibleInterface) Address() common.Address { return _StreamsLookupCompatibleInterface.address @@ -194,5 +228,9 @@ type StreamsLookupCompatibleInterfaceInterface interface { error) + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + Address() common.Address } diff --git a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go index d54ee36f8ff..d1ea0bcdbd1 100644 --- a/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/streams_lookup_upkeep_wrapper/streams_lookup_upkeep_wrapper.go @@ -31,8 +31,8 @@ var ( ) var StreamsLookupUpkeepMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"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\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"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\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001a6a38038062001a6a83398101604081905262000034916200020f565b60008581556001859055600281905560038190556004558215156080526040805180820190915260078152666665656449447360c81b60208201526006906200007e908262000312565b50604080518082019091526009815268074696d657374616d760bc1b6020820152600790620000ae908262000312565b50604051806020016040528060405180608001604052806042815260200162001a28604291399052620000e690600590600162000122565b506008805463ff000000199215156101000261ff00199415159490941661ffff19909116179290921716630100000017905550620003de915050565b8280548282559060005260206000209081019282156200016d579160200282015b828111156200016d57825182906200015c908262000312565b509160200191906001019062000143565b506200017b9291506200017f565b5090565b808211156200017b576000620001968282620001a0565b506001016200017f565b508054620001ae9062000283565b6000825580601f10620001bf575050565b601f016020900490600052602060002090810190620001df9190620001e2565b50565b5b808211156200017b5760008155600101620001e3565b805180151581146200020a57600080fd5b919050565b600080600080600060a086880312156200022857600080fd5b85519450602086015193506200024160408701620001f9565b92506200025160608701620001f9565b91506200026160808701620001f9565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029857607f821691505b602082108103620002b957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200030d57600081815260208120601f850160051c81016020861015620002e85750805b601f850160051c820191505b818110156200030957828155600101620002f4565b5050505b505050565b81516001600160401b038111156200032e576200032e6200026d565b62000346816200033f845462000283565b84620002bf565b602080601f8311600181146200037e5760008415620003655750858301515b600019600386901b1c1916600185901b17855562000309565b600085815260208120601f198616915b82811015620003af578886015182559484019460019091019084016200038e565b5085821015620003ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516116196200040f60003960008181610307015281816103900152818161090c0152610a7b01526116196000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80636e04ff0d116100d8578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461035e578063d832d92f14610372578063fc735e991461037a57600080fd5b8063947a36fb14610345578063afb28d1f1461034e578063c98f10b01461035657600080fd5b806386b728e2116100bd57806386b728e21461030257806386e330af14610329578063917d895f1461033c57600080fd5b80636e04ff0d146102dc5780638340507c146102ef57600080fd5b80634a5479f31161013a5780635b48391a116101145780635b48391a1461028357806361bc221a146102ca5780636250a13a146102d357600080fd5b80634a5479f3146101fc5780634b56a42e1461021c5780634bdb38621461023d57600080fd5b80631d1970b71161016b5780631d1970b7146101c35780632cb15864146101d05780634585e33b146101e757600080fd5b806302be021f14610187578063102d538b146101af575b600080fd5b60085461019a9062010000900460ff1681565b60405190151581526020015b60405180910390f35b60085461019a906301000000900460ff1681565b60085461019a9060ff1681565b6101d960035481565b6040519081526020016101a6565b6101fa6101f5366004610c0f565b61038c565b005b61020f61020a366004610c81565b6106b9565b6040516101a69190610d08565b61022f61022a366004610e60565b610765565b6040516101a6929190610f34565b6101fa61024b366004610f57565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6101fa610291366004610f57565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b6101d960045481565b6101d960005481565b61022f6102ea366004610c0f565b610840565b6101fa6102fd366004610f79565b610a16565b61019a7f000000000000000000000000000000000000000000000000000000000000000081565b6101fa610337366004610fc6565b610a34565b6101d960025481565b6101d960015481565b61020f610a4b565b61020f610a58565b6101fa600060028190556003819055600455565b61019a610a65565b60085461019a90610100900460ff1681565b60007f00000000000000000000000000000000000000000000000000000000000000001561042b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104249190611077565b905061042e565b50435b60035460000361043e5760038190555b60008061044d84860186610e60565b600285905560045491935091506104659060016110bf565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156106435760085460ff1615610574577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106104e4576104e46110d8565b60200260200101516040518263ffffffff1660e01b81526004016105089190610d08565b6000604051808303816000875af1158015610527573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261056d9190810190611107565b9150610643565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106105b7576105b76110d8565b60200260200101516040518263ffffffff1660e01b81526004016105db9190610d08565b6000604051808303816000875af11580156105fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106409190810190611107565b91505b843373ffffffffffffffffffffffffffffffffffffffff167ff0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda13908660008151811061068f5761068f6110d8565b602002602001015185876040516106a89392919061117e565b60405180910390a350505050505050565b600581815481106106c957600080fd5b9060005260206000200160009150905080546106e4906111c1565b80601f0160208091040260200160405190810160405280929190818152602001828054610710906111c1565b801561075d5780601f106107325761010080835404028352916020019161075d565b820191906000526020600020905b81548152906001019060200180831161074057829003601f168201915b505050505081565b60085460009060609062010000900460ff16156107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b600084846040516020016107f8929190611214565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff1693509150505b9250929050565b6000606061084c610a65565b610898576000848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959750919550610839945050505050565b6040517f666565644964486578000000000000000000000000000000000000000000000060208201526000906029016040516020818303038152906040528051906020012060066040516020016108ef919061129f565b60405160208183030381529060405280519060200120036109ae577f0000000000000000000000000000000000000000000000000000000000000000156109a757606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561097c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a09190611077565b90506109b1565b50436109b1565b50425b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a2000000000000000000000000000000000000000000000000000000009092526107da916006916005916007918691906038016113ce565b6006610a2283826114df565b506007610a2f82826114df565b505050565b8051610a47906005906020840190610b4a565b5050565b600680546106e4906111c1565b600780546106e4906111c1565b6000600354600003610a775750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610b1657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0f9190611077565b9050610b19565b50435b600054600354610b2990836115f9565b108015610b445750600154600254610b4190836115f9565b10155b91505090565b828054828255906000526020600020908101928215610b90579160200282015b82811115610b905782518290610b8090826114df565b5091602001919060010190610b6a565b50610b9c929150610ba0565b5090565b80821115610b9c576000610bb48282610bbd565b50600101610ba0565b508054610bc9906111c1565b6000825580601f10610bd9575050565b601f016020900490600052602060002090810190610bf79190610bfa565b50565b5b80821115610b9c5760008155600101610bfb565b60008060208385031215610c2257600080fd5b823567ffffffffffffffff80821115610c3a57600080fd5b818501915085601f830112610c4e57600080fd5b813581811115610c5d57600080fd5b866020828501011115610c6f57600080fd5b60209290920196919550909350505050565b600060208284031215610c9357600080fd5b5035919050565b60005b83811015610cb5578181015183820152602001610c9d565b50506000910152565b60008151808452610cd6816020860160208601610c9a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610d1b6020830184610cbe565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d9857610d98610d22565b604052919050565b600067ffffffffffffffff821115610dba57610dba610d22565b5060051b60200190565b600067ffffffffffffffff821115610dde57610dde610d22565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610e1b57600080fd5b8135610e2e610e2982610dc4565b610d51565b818152846020838601011115610e4357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610e7357600080fd5b823567ffffffffffffffff80821115610e8b57600080fd5b818501915085601f830112610e9f57600080fd5b81356020610eaf610e2983610da0565b82815260059290921b84018101918181019089841115610ece57600080fd5b8286015b84811015610f0657803586811115610eea5760008081fd5b610ef88c86838b0101610e0a565b845250918301918301610ed2565b5096505086013592505080821115610f1d57600080fd5b50610f2a85828601610e0a565b9150509250929050565b8215158152604060208201526000610f4f6040830184610cbe565b949350505050565b600060208284031215610f6957600080fd5b81358015158114610d1b57600080fd5b60008060408385031215610f8c57600080fd5b823567ffffffffffffffff80821115610fa457600080fd5b610fb086838701610e0a565b93506020850135915080821115610f1d57600080fd5b60006020808385031215610fd957600080fd5b823567ffffffffffffffff80821115610ff157600080fd5b818501915085601f83011261100557600080fd5b8135611013610e2982610da0565b81815260059190911b8301840190848101908883111561103257600080fd5b8585015b8381101561106a5780358581111561104e5760008081fd5b61105c8b89838a0101610e0a565b845250918601918601611036565b5098975050505050505050565b60006020828403121561108957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156110d2576110d2611090565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561111957600080fd5b815167ffffffffffffffff81111561113057600080fd5b8201601f8101841361114157600080fd5b805161114f610e2982610dc4565b81815285602083850101111561116457600080fd5b611175826020830160208601610c9a565b95945050505050565b6060815260006111916060830186610cbe565b82810360208401526111a38186610cbe565b905082810360408401526111b78185610cbe565b9695505050505050565b600181811c908216806111d557607f821691505b60208210810361120e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611289577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611277868351610cbe565b9550938201939082019060010161123d565b5050858403818701525050506111758185610cbe565b60008083546112ad816111c1565b600182811680156112c557600181146112f857611327565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450611327565b8760005260208060002060005b8581101561131e5781548a820152908401908201611305565b50505082870194505b50929695505050505050565b60008154611340816111c1565b80855260206001838116801561135d5760018114611395576113c3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506113c3565b866000528260002060005b858110156113bb5781548a82018601529083019084016113a0565b890184019650505b505050505092915050565b60a0815260006113e160a0830188611333565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015611453577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526114418383611333565b94860194925060019182019101611408565b50508681036040880152611467818b611333565b94505050505084606084015282810360808401526114858185610cbe565b98975050505050505050565b601f821115610a2f57600081815260208120601f850160051c810160208610156114b85750805b601f850160051c820191505b818110156114d7578281556001016114c4565b505050505050565b815167ffffffffffffffff8111156114f9576114f9610d22565b61150d8161150784546111c1565b84611491565b602080601f831160018114611560576000841561152a5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114d7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156115ad5788860151825594840194600190910190840161158e565b50858210156115e957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b818103818111156110d2576110d261109056fea164736f6c6343000810000a307830303032386339313564366166306664363662626132643066633934303532323662636138643638303633333331323161376439383332313033643135363363", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useArbBlock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_staging\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"v0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verifiedV0\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"ed\",\"type\":\"bytes\"}],\"name\":\"MercuryPerformEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"callbackReturnBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"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\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feeds\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"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\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setCallbackReturnBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRevertCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRevertCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"staging\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbBlock\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001adb38038062001adb83398101604081905262000034916200020f565b60008581556001859055600281905560038190556004558215156080526040805180820190915260078152666665656449447360c81b60208201526006906200007e908262000312565b50604080518082019091526009815268074696d657374616d760bc1b6020820152600790620000ae908262000312565b50604051806020016040528060405180608001604052806042815260200162001a99604291399052620000e690600590600162000122565b506008805463ff000000199215156101000261ff00199415159490941661ffff19909116179290921716630100000017905550620003de915050565b8280548282559060005260206000209081019282156200016d579160200282015b828111156200016d57825182906200015c908262000312565b509160200191906001019062000143565b506200017b9291506200017f565b5090565b808211156200017b576000620001968282620001a0565b506001016200017f565b508054620001ae9062000283565b6000825580601f10620001bf575050565b601f016020900490600052602060002090810190620001df9190620001e2565b50565b5b808211156200017b5760008155600101620001e3565b805180151581146200020a57600080fd5b919050565b600080600080600060a086880312156200022857600080fd5b85519450602086015193506200024160408701620001f9565b92506200025160608701620001f9565b91506200026160808701620001f9565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029857607f821691505b602082108103620002b957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200030d57600081815260208120601f850160051c81016020861015620002e85750805b601f850160051c820191505b818110156200030957828155600101620002f4565b5050505b505050565b81516001600160401b038111156200032e576200032e6200026d565b62000346816200033f845462000283565b84620002bf565b602080601f8311600181146200037e5760008415620003655750858301515b600019600386901b1c1916600185901b17855562000309565b600085815260208120601f198616915b82811015620003af578886015182559484019460019091019084016200038e565b5085821015620003ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161168a6200040f60003960008181610325015281816103c6015281816109400152610aaf015261168a6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80636250a13a116100e3578063947a36fb1161008c578063d826f88f11610066578063d826f88f1461037c578063d832d92f14610390578063fc735e991461039857600080fd5b8063947a36fb14610363578063afb28d1f1461036c578063c98f10b01461037457600080fd5b806386b728e2116100bd57806386b728e21461032057806386e330af14610347578063917d895f1461035a57600080fd5b80636250a13a146102f15780636e04ff0d146102fa5780638340507c1461030d57600080fd5b80634585e33b116101455780634bdb38621161011f5780634bdb38621461025b5780635b48391a146102a157806361bc221a146102e857600080fd5b80634585e33b146102135780634a5479f3146102285780634b56a42e1461024857600080fd5b8063102d538b11610176578063102d538b146101db5780631d1970b7146101ef5780632cb15864146101fc57600080fd5b806302be021f146101925780630fb172fb146101ba575b600080fd5b6008546101a59062010000900460ff1681565b60405190151581526020015b60405180910390f35b6101cd6101c8366004610d5d565b6103aa565b6040516101b1929190610e12565b6008546101a5906301000000900460ff1681565b6008546101a59060ff1681565b61020560035481565b6040519081526020016101b1565b610226610221366004610e35565b6103c2565b005b61023b610236366004610ea7565b6106ef565b6040516101b19190610ec0565b6101cd610256366004610efe565b61079b565b610226610269366004610fc8565b6008805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b6102266102af366004610fc8565b600880549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff909216919091179055565b61020560045481565b61020560005481565b6101cd610308366004610e35565b610874565b61022661031b366004610fea565b610a4a565b6101a57f000000000000000000000000000000000000000000000000000000000000000081565b610226610355366004611037565b610a68565b61020560025481565b61020560015481565b61023b610a7f565b61023b610a8c565b610226600060028190556003819055600455565b6101a5610a99565b6008546101a590610100900460ff1681565b604080516000808252602082019092525b9250929050565b60007f00000000000000000000000000000000000000000000000000000000000000001561046157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045a91906110e8565b9050610464565b50435b6003546000036104745760038190555b60008061048384860186610efe565b6002859055600454919350915061049b906001611130565b600455604080516020808201835260008083528351918201909352918252600854909190610100900460ff16156106795760085460ff16156105aa577360448b880c9f3b501af3f343da9284148bd7d77c73ffffffffffffffffffffffffffffffffffffffff16638e760afe8560008151811061051a5761051a611149565b60200260200101516040518263ffffffff1660e01b815260040161053e9190610ec0565b6000604051808303816000875af115801561055d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105a39190810190611178565b9150610679565b7309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe856000815181106105ed576105ed611149565b60200260200101516040518263ffffffff1660e01b81526004016106119190610ec0565b6000604051808303816000875af1158015610630573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106769190810190611178565b91505b843373ffffffffffffffffffffffffffffffffffffffff167ff0f72c0b235fc8687d6a67c02ca543473a3cef8a18b48490f10e475a8dda1390866000815181106106c5576106c5611149565b602002602001015185876040516106de939291906111ef565b60405180910390a350505050505050565b600581815481106106ff57600080fd5b90600052602060002001600091509050805461071a90611232565b80601f016020809104026020016040519081016040528092919081815260200182805461074690611232565b80156107935780601f1061076857610100808354040283529160200191610793565b820191906000526020600020905b81548152906001019060200180831161077657829003601f168201915b505050505081565b60085460009060609062010000900460ff1615610819576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73686f756c6452657665727443616c6c6261636b20697320747275650000000060448201526064015b60405180910390fd5b6000848460405160200161082e929190611285565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526008546301000000900460ff16969095509350505050565b60006060610880610a99565b6108cc576000848481818080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509597509195506103bb945050505050565b6040517f666565644964486578000000000000000000000000000000000000000000000060208201526000906029016040516020818303038152906040528051906020012060066040516020016109239190611310565b60405160208183030381529060405280519060200120036109e2577f0000000000000000000000000000000000000000000000000000000000000000156109db57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d491906110e8565b90506109e5565b50436109e5565b50425b604080516c6400000000000000000000000060208201528151601481830301815260348201928390527ff055e4a2000000000000000000000000000000000000000000000000000000009092526108109160069160059160079186919060380161143f565b6006610a568382611550565b506007610a638282611550565b505050565b8051610a7b906005906020840190610b7e565b5050565b6006805461071a90611232565b6007805461071a90611232565b6000600354600003610aab5750600190565b60007f000000000000000000000000000000000000000000000000000000000000000015610b4a57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4391906110e8565b9050610b4d565b50435b600054600354610b5d908361166a565b108015610b785750600154600254610b75908361166a565b10155b91505090565b828054828255906000526020600020908101928215610bc4579160200282015b82811115610bc45782518290610bb49082611550565b5091602001919060010190610b9e565b50610bd0929150610bd4565b5090565b80821115610bd0576000610be88282610bf1565b50600101610bd4565b508054610bfd90611232565b6000825580601f10610c0d575050565b601f016020900490600052602060002090810190610c2b9190610c2e565b50565b5b80821115610bd05760008155600101610c2f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610cb957610cb9610c43565b604052919050565b600067ffffffffffffffff821115610cdb57610cdb610c43565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610d1857600080fd5b8135610d2b610d2682610cc1565b610c72565b818152846020838601011115610d4057600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610d7057600080fd5b82359150602083013567ffffffffffffffff811115610d8e57600080fd5b610d9a85828601610d07565b9150509250929050565b60005b83811015610dbf578181015183820152602001610da7565b50506000910152565b60008151808452610de0816020860160208601610da4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000610e2d6040830184610dc8565b949350505050565b60008060208385031215610e4857600080fd5b823567ffffffffffffffff80821115610e6057600080fd5b818501915085601f830112610e7457600080fd5b813581811115610e8357600080fd5b866020828501011115610e9557600080fd5b60209290920196919550909350505050565b600060208284031215610eb957600080fd5b5035919050565b602081526000610ed36020830184610dc8565b9392505050565b600067ffffffffffffffff821115610ef457610ef4610c43565b5060051b60200190565b60008060408385031215610f1157600080fd5b823567ffffffffffffffff80821115610f2957600080fd5b818501915085601f830112610f3d57600080fd5b81356020610f4d610d2683610eda565b82815260059290921b84018101918181019089841115610f6c57600080fd5b8286015b84811015610fa457803586811115610f885760008081fd5b610f968c86838b0101610d07565b845250918301918301610f70565b5096505086013592505080821115610fbb57600080fd5b50610d9a85828601610d07565b600060208284031215610fda57600080fd5b81358015158114610ed357600080fd5b60008060408385031215610ffd57600080fd5b823567ffffffffffffffff8082111561101557600080fd5b61102186838701610d07565b93506020850135915080821115610fbb57600080fd5b6000602080838503121561104a57600080fd5b823567ffffffffffffffff8082111561106257600080fd5b818501915085601f83011261107657600080fd5b8135611084610d2682610eda565b81815260059190911b830184019084810190888311156110a357600080fd5b8585015b838110156110db578035858111156110bf5760008081fd5b6110cd8b89838a0101610d07565b8452509186019186016110a7565b5098975050505050505050565b6000602082840312156110fa57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561114357611143611101565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561118a57600080fd5b815167ffffffffffffffff8111156111a157600080fd5b8201601f810184136111b257600080fd5b80516111c0610d2682610cc1565b8181528560208385010111156111d557600080fd5b6111e6826020830160208601610da4565b95945050505050565b6060815260006112026060830186610dc8565b82810360208401526112148186610dc8565b905082810360408401526112288185610dc8565b9695505050505050565b600181811c9082168061124657607f821691505b60208210810361127f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156112fa577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526112e8868351610dc8565b955093820193908201906001016112ae565b5050858403818701525050506111e68185610dc8565b600080835461131e81611232565b60018281168015611336576001811461136957611398565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450611398565b8760005260208060002060005b8581101561138f5781548a820152908401908201611376565b50505082870194505b50929695505050505050565b600081546113b181611232565b8085526020600183811680156113ce576001811461140657611434565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550611434565b866000528260002060005b8581101561142c5781548a8201860152908301908401611411565b890184019650505b505050505092915050565b60a08152600061145260a08301886113a4565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156114c4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526114b283836113a4565b94860194925060019182019101611479565b505086810360408801526114d8818b6113a4565b94505050505084606084015282810360808401526114f68185610dc8565b98975050505050505050565b601f821115610a6357600081815260208120601f850160051c810160208610156115295750805b601f850160051c820191505b8181101561154857828155600101611535565b505050505050565b815167ffffffffffffffff81111561156a5761156a610c43565b61157e816115788454611232565b84611502565b602080601f8311600181146115d1576000841561159b5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611548565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561161e578886015182559484019460019091019084016115ff565b508582101561165a57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b818103818111156111435761114361110156fea164736f6c6343000810000a307830303032386339313564366166306664363662626132643066633934303532323662636138643638303633333331323161376439383332313033643135363363", } var StreamsLookupUpkeepABI = StreamsLookupUpkeepMetaData.ABI @@ -216,6 +216,36 @@ func (_StreamsLookupUpkeep *StreamsLookupUpkeepCallerSession) CheckCallback(valu return _StreamsLookupUpkeep.Contract.CheckCallback(&_StreamsLookupUpkeep.CallOpts, values, extraData) } +func (_StreamsLookupUpkeep *StreamsLookupUpkeepCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _StreamsLookupUpkeep.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_StreamsLookupUpkeep *StreamsLookupUpkeepSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _StreamsLookupUpkeep.Contract.CheckErrorHandler(&_StreamsLookupUpkeep.CallOpts, errCode, extraData) +} + +func (_StreamsLookupUpkeep *StreamsLookupUpkeepCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _StreamsLookupUpkeep.Contract.CheckErrorHandler(&_StreamsLookupUpkeep.CallOpts, errCode, extraData) +} + func (_StreamsLookupUpkeep *StreamsLookupUpkeepCaller) CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) { var out []interface{} err := _StreamsLookupUpkeep.contract.Call(opts, &out, "checkUpkeep", data) @@ -736,6 +766,11 @@ func (_StreamsLookupUpkeep *StreamsLookupUpkeepFilterer) ParseMercuryPerformEven return event, nil } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} + func (_StreamsLookupUpkeep *StreamsLookupUpkeep) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _StreamsLookupUpkeep.abi.Events["MercuryPerformEvent"].ID: @@ -759,6 +794,10 @@ type StreamsLookupUpkeepInterface interface { CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) Counter(opts *bind.CallOpts) (*big.Int, error) diff --git a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go index 9648c4bd719..db821ffe330 100644 --- a/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_log_trigger_upkeep_wrapper/verifiable_load_log_trigger_upkeep_wrapper.go @@ -55,8 +55,8 @@ type Log struct { } var VerifiableLoadLogTriggerUpkeepMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_useMercury\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"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\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"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\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"logNum\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_log\",\"type\":\"uint8\"}],\"name\":\"setLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useMercury\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620066ec6101603981526020016040518060800160405280604281526020016200672e604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b506040516200677038038062006770833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615f926200075a600039600081816105b90152612551015260008181610a2d01526140920152600081816108a601528181611fa80152613ae0015260008181610dca01528181611f780152613ab50152615f926000f3fe6080604052600436106105265760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb14611066578063fba7ffa314611119578063fcdc1f631461114657600080fd5b8063e83ce55814611027578063f2fde38b1461104657600080fd5b8063de818253116100bb578063de81825314610f90578063e0114adb14610fe4578063e45530831461101157600080fd5b8063daee1aeb14610f50578063dbef701e14610f7057600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610ef0578063d6051a7214610f10578063da6cba4714610f3057600080fd5b8063c41c815b14610ec1578063c98f10b014610edb57600080fd5b8063b657bc9c1161015e578063b657bc9c14610e61578063becde0e114610e81578063c041982214610ea157600080fd5b8063af953a4a14610e2c578063afb28d1f14610e4c57600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610db8578063a6b5947514610dec578063a72aa27e14610e0c57600080fd5b80639d385eaa14610d785780639d6f1cc714610d9857600080fd5b80639ac542eb1161020c5780639ac542eb14610cf05780639b42935414610d1a5780639b51fb0d14610d4757600080fd5b8063948108f714610cb057806396cebc7c14610cd057600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c385780638fcb3fba14610c63578063924ca57814610c9057600080fd5b806386e330af14610bf8578063873c758614610c1857600080fd5b80637b10399914610b6b5780637e7a46dc14610b985780638243444a14610bb85780638340507c14610bd857600080fd5b806345d2ec17116103f057806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b1657806379ba509714610b3657806379ea994314610b4b57600080fd5b806373644cce14610abc5780637672130314610ae957600080fd5b8063642f6cef1161034d578063642f6cef14610a1b57806369cdbadb14610a5f5780637145f11b14610a8c57600080fd5b806360457ff5146109c9578063636092e8146109f657600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109675780635d4ee7f3146109945780635f17e616146109a957600080fd5b80635147cd591461091557806351c98be31461094757600080fd5b806345d2ec1714610867578063469820931461089457806346e7a63e146108c85780634b56a42e146108f557600080fd5b806320e3dbd41161049e5780632b20e397116104525780633ebe8d6c116104375780633ebe8d6c146107f957806340691db4146108195780634585e33b1461084757600080fd5b80632b20e3971461077a578063328ffd11146107cc57600080fd5b806328c4b57b1161048357806328c4b57b1461070d57806329e0a8411461072d5780632a9032d31461075a57600080fd5b806320e3dbd4146106cd5780632636aecf146106ed57600080fd5b806319d97a94116104f55780631e010439116104da5780631e0104391461063b578063206c32e814610678578063207b6516146106ad57600080fd5b806319d97a94146105ee5780631cdde2511461061b57600080fd5b806306c1cc0014610532578063077ac621146105545780630b7d33e61461058757806312c55027146105a757600080fd5b3661052d57005b600080fd5b34801561053e57600080fd5b5061055261054d366004614814565b611173565b005b34801561056057600080fd5b5061057461056f3660046148c7565b6113c2565b6040519081526020015b60405180910390f35b34801561059357600080fd5b506105526105a23660046148fc565b611400565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161057e565b3480156105fa57600080fd5b5061060e610609366004614943565b61148e565b60405161057e91906149ca565b34801561062757600080fd5b506105526106363660046149ff565b61154b565b34801561064757600080fd5b5061065b610656366004614943565b611688565b6040516bffffffffffffffffffffffff909116815260200161057e565b34801561068457600080fd5b50610698610693366004614a64565b61171d565b6040805192835260208301919091520161057e565b3480156106b957600080fd5b5061060e6106c8366004614943565b6117a0565b3480156106d957600080fd5b506105526106e8366004614a90565b6117f8565b3480156106f957600080fd5b50610552610708366004614af2565b6119c2565b34801561071957600080fd5b50610574610728366004614b6c565b611c8b565b34801561073957600080fd5b5061074d610748366004614943565b611cf6565b60405161057e9190614b98565b34801561076657600080fd5b50610552610775366004614cd9565b611dfb565b34801561078657600080fd5b506011546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161057e565b3480156107d857600080fd5b506105746107e7366004614943565b60036020526000908152604090205481565b34801561080557600080fd5b50610574610814366004614943565b611edc565b34801561082557600080fd5b50610839610834366004614d1b565b611f45565b60405161057e929190614d7e565b34801561085357600080fd5b50610552610862366004614ddb565b61244b565b34801561087357600080fd5b50610887610882366004614a64565b61269a565b60405161057e9190614e11565b3480156108a057600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d457600080fd5b506105746108e3366004614943565b600a6020526000908152604090205481565b34801561090157600080fd5b50610839610910366004614e79565b612709565b34801561092157600080fd5b50610935610930366004614943565b61275d565b60405160ff909116815260200161057e565b34801561095357600080fd5b50610552610962366004614f36565b6127f1565b34801561097357600080fd5b506012546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a057600080fd5b50610552612895565b3480156109b557600080fd5b506105526109c4366004614f8d565b6129d0565b3480156109d557600080fd5b506105746109e4366004614943565b60076020526000908152604090205481565b348015610a0257600080fd5b5060155461065b906bffffffffffffffffffffffff1681565b348015610a2757600080fd5b50610a4f7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161057e565b348015610a6b57600080fd5b50610574610a7a366004614943565b60086020526000908152604090205481565b348015610a9857600080fd5b50610a4f610aa7366004614943565b600b6020526000908152604090205460ff1681565b348015610ac857600080fd5b50610574610ad7366004614943565b6000908152600c602052604090205490565b348015610af557600080fd5b50610574610b04366004614943565b60046020526000908152604090205481565b348015610b2257600080fd5b50610a4f610b31366004614943565b612a9d565b348015610b4257600080fd5b50610552612aef565b348015610b5757600080fd5b506107a7610b66366004614943565b612bec565b348015610b7757600080fd5b506013546107a79073ffffffffffffffffffffffffffffffffffffffff1681565b348015610ba457600080fd5b50610552610bb3366004614faf565b612c80565b348015610bc457600080fd5b50610552610bd3366004614faf565b612d11565b348015610be457600080fd5b50610552610bf3366004614ffb565b612d6b565b348015610c0457600080fd5b50610552610c13366004615048565b612d89565b348015610c2457600080fd5b50610887610c33366004614f8d565b612d9c565b348015610c4457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107a7565b348015610c6f57600080fd5b50610574610c7e366004614943565b60056020526000908152604090205481565b348015610c9c57600080fd5b50610552610cab366004614f8d565b612e59565b348015610cbc57600080fd5b50610552610ccb3660046150f9565b61309e565b348015610cdc57600080fd5b50610552610ceb366004615129565b6131b6565b348015610cfc57600080fd5b50601554610935906c01000000000000000000000000900460ff1681565b348015610d2657600080fd5b50610552610d35366004614f8d565b60009182526009602052604090912055565b348015610d5357600080fd5b506105db610d62366004614943565b600e6020526000908152604090205461ffff1681565b348015610d8457600080fd5b50610887610d93366004614943565b6133c0565b348015610da457600080fd5b5061060e610db3366004614943565b613422565b348015610dc457600080fd5b506105747f000000000000000000000000000000000000000000000000000000000000000081565b348015610df857600080fd5b50610552610e07366004614b6c565b6134ce565b348015610e1857600080fd5b50610552610e27366004615146565b613537565b348015610e3857600080fd5b50610552610e47366004614943565b6135e2565b348015610e5857600080fd5b5061060e613668565b348015610e6d57600080fd5b5061065b610e7c366004614943565b613675565b348015610e8d57600080fd5b50610552610e9c366004614cd9565b6136cd565b348015610ead57600080fd5b50610887610ebc366004614f8d565b613767565b348015610ecd57600080fd5b50601954610a4f9060ff1681565b348015610ee757600080fd5b5061060e613864565b348015610efc57600080fd5b50610552610f0b36600461516b565b613871565b348015610f1c57600080fd5b50610698610f2b366004614f8d565b6138f0565b348015610f3c57600080fd5b50610552610f4b366004615190565b613959565b348015610f5c57600080fd5b50610552610f6b366004614cd9565b613cc0565b348015610f7c57600080fd5b50610574610f8b366004614f8d565b613d8b565b348015610f9c57600080fd5b50610552610fab366004615129565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b348015610ff057600080fd5b50610574610fff366004614943565b60096020526000908152604090205481565b34801561101d57600080fd5b5061057460145481565b34801561103357600080fd5b5060195461093590610100900460ff1681565b34801561105257600080fd5b50610552611061366004614a90565b613dbc565b34801561107257600080fd5b5061060e6110813660046151f8565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561112557600080fd5b50610574611134366004614943565b60066020526000908152604090205481565b34801561115257600080fd5b50610574611161366004614943565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611259908c1688615280565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb91906152c4565b5060008860ff1667ffffffffffffffff81111561131a5761131a6146b6565b604051908082528060200260200182016040528015611343578160200160208202803683370190505b50905060005b8960ff168160ff1610156113b657600061136284613dd0565b905080838360ff168151811061137a5761137a6152df565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113ae8161530e565b915050611349565b50505050505050505050565b600d60205282600052604060002060205281600052604060002081815481106113ea57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611458908590859060040161532d565b600060405180830381600087803b15801561147257600080fd5b505af1158015611486573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115459190810190615393565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa1580156115ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526116309190810190615393565b6040518363ffffffff1660e01b815260040161164d92919061532d565b600060405180830381600087803b15801561166757600080fd5b505af115801561167b573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa1580156116f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154591906153d3565b6000828152600d6020908152604080832061ffff85168452825280832080548251818502810185019093528083528493849392919083018282801561178157602002820191906000526020600020905b81548152602001906001019080831161176d575b50505050509050611793818251613e9e565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b6516906024016114e2565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa15801561188e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b291906153fb565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190615429565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611c805760008989838181106119e2576119e26152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a1b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a4792919061532d565b600060405180830381600087803b158015611a6157600080fd5b505af1158015611a75573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0f9190615446565b90508060ff16600103611c6b576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b98573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611bde9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c37908690859060040161532d565b600060405180830381600087803b158015611c5157600080fd5b505af1158015611c65573d6000803e3d6000fd5b50505050505b50508080611c7890615463565b9150506119c6565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611cec93830182828015611ce057602002820191906000526020600020905b815481526020019060010190808311611ccc575b50505050508484613f23565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611db5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261154591908101906154be565b8060005b818160ff161015611ed65760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e3d57611e3d6152df565b905060200201356040518263ffffffff1660e01b8152600401611e6291815260200190565b600060405180830381600087803b158015611e7c57600080fd5b505af1158015611e90573d6000803e3d6000fd5b50505050611ec384848360ff16818110611eac57611eac6152df565b90506020020135600f61408290919063ffffffff16565b5080611ece8161530e565b915050611dff565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f3d576000858152600d6020908152604080832061ffff85168452909152902054611f2990836155dd565b915080611f35816155f0565b915050611ef2565b509392505050565b6000606060005a90506000611f5861408e565b9050600085806020019051810190611f709190615611565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff1615611fc857507f00000000000000000000000000000000000000000000000000000000000000005b80611fd660c08a018a61562a565b6000818110611fe757611fe76152df565b90506020020135036123e957600061200260c08a018a61562a565b6001818110612013576120136152df565b9050602002013560405160200161202c91815260200190565b60405160208183030381529060405290506000818060200190518101906120539190615611565b90508381146120c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b60006120d260c08c018c61562a565b60028181106120e3576120e36152df565b905060200201356040516020016120fc91815260200190565b60405160208183030381529060405290506000818060200190518101906121239190615611565b9050600061213460c08e018e61562a565b6003818110612145576121456152df565b9050602002013560405160200161215e91815260200190565b60405160208183030381529060405290506000818060200190518101906121859190615429565b6000868152600860205260409020549091505b805a6121a4908d615692565b6121b090613a986155dd565b10156121f15783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612198565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161224891906156f8565b604051602081830303815290604052805190602001200361226a57508361226d565b50425b60195460ff161561231557604080516020810189905290810186905273ffffffffffffffffffffffffffffffffffffffff841660608201526017906016906018908490608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526120ba9594939291600401615827565b60165460009067ffffffffffffffff811115612333576123336146b6565b60405190808252806020026020018201604052801561236657816020015b60608152602001906001900390816123515790505b5060408051602081018b905290810188905273ffffffffffffffffffffffffffffffffffffffff861660608201529091506000906080016040516020818303038152906040529050600182826040516020016123c39291906158ea565b6040516020818303038152906040529f509f505050505050505050505050505050611799565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e742073696700000000000000000000000060448201526064016120ba565b60005a905060008061245f84860186614e79565b9150915060008060008380602001905181019061247c919061597e565b60008381526005602090815260408083205460049092528220549497509295509093509091906124aa61408e565b9050826000036124ca57600086815260056020526040902081905561260e565b60006124d68683615692565b6000888152600e6020908152604080832054600d835281842061ffff90911680855290835281842080548351818602810186019094528084529596509094919290919083018282801561254857602002820191906000526020600020905b815481526020019060010190808311612534575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff168151036125c35781612585816155f0565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b6000868152600660205260408120546126289060016155dd565b60008881526006602090815260408083208490556004909152902083905590506126528783612e59565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a461268c878b846134ce565b505050505050505050505050565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156126fc57602002820191906000526020600020905b8154815260200190600101908083116126e8575b5050505050905092915050565b60006060600084846040516020016127229291906158ea565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156127cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615446565b8160005b8181101561288e5730635f17e616868684818110612815576128156152df565b90506020020135856040518363ffffffff1660e01b815260040161284992919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561286357600080fd5b505af1158015612877573d6000803e3d6000fd5b50505050808061288690615463565b9150506127f5565b5050505050565b61289d614130565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190615611565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156129a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129cc91906152c4565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c9091528120612a08916145b5565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612a64576000848152600d6020908152604080832061ffff851684529091528120612a52916145b5565b80612a5c816155f0565b915050612a1d565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612aba57506001919050565b600082815260036020908152604080832054600490925290912054612add61408e565b612ae79190615692565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016120ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612c5c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615429565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612cda908690869086906004016159ac565b600060405180830381600087803b158015612cf457600080fd5b505af1158015612d08573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612cda908690869086906004016159ac565b6017612d778382615a46565b506018612d848282615a46565b505050565b80516129cc9060169060208401906145d3565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cef9190810190615b60565b601454600083815260026020526040902054612e759083615692565b11156129cc576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f3191908101906154be565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fca91906153d3565b601554909150612fee9082906c01000000000000000000000000900460ff16615280565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611ed6576015546130319085906bffffffffffffffffffffffff1661309e565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314a91906152c4565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611458565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613215573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261325b9190810190615b60565b8051909150600061326a61408e565b905060005b8281101561288e57600084828151811061328b5761328b6152df565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f9190615446565b90508060ff166001036133ab578660ff1660000361337b576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46133ab565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b505080806133b890615463565b91505061326f565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561341657602002820191906000526020600020905b815481526020019060010190808311613402575b50505050509050919050565b6016818154811061343257600080fd5b90600052602060002001600091509050805461344d906156a5565b80601f0160208091040260200160405190810160405280929190818152602001828054613479906156a5565b80156134c65780601f1061349b576101008083540402835291602001916134c6565b820191906000526020600020905b8154815290600101906020018083116134a957829003601f168201915b505050505081565b6000838152600760205260409020545b805a6134ea9085615692565b6134f6906127106155dd565b1015611ed65781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556134de565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156135af57600080fd5b505af11580156135c3573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561365457600080fd5b505af115801561288e573d6000803e3d6000fd5b6017805461344d906156a5565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016116dc565b8060005b818163ffffffff161015611ed6573063af953a4a858563ffffffff85168181106136fd576136fd6152df565b905060200201356040518263ffffffff1660e01b815260040161372291815260200190565b600060405180830381600087803b15801561373c57600080fd5b505af1158015613750573d6000803e3d6000fd5b50505050808061375f90615bf1565b9150506136d1565b60606000613775600f6141b3565b90508084106137b0576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036137c5576137c28482615692565b92505b60008367ffffffffffffffff8111156137e0576137e06146b6565b604051908082528060200260200182016040528015613809578160200160208202803683370190505b50905060005b8481101561385b5761382c61382482886155dd565b600f906141bd565b82828151811061383e5761383e6152df565b60209081029190910101528061385381615463565b91505061380f565b50949350505050565b6018805461344d906156a5565b600061387b61408e565b90508160ff166000036138bc576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561394857602002820191906000526020600020905b815481526020019060010190808311613934575b505050505090506117938185613e9e565b8260005b81811015611486576000868683818110613979576139796152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016139b291815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016139de92919061532d565b600060405180830381600087803b1580156139f857600080fd5b505af1158015613a0c573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa69190615446565b90508060ff16600103613cab577f000000000000000000000000000000000000000000000000000000000000000060ff871615613b0057507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613b3491815260200190565b604051602081830303815290604052613b4c90615c0a565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613bd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613c1d9190810190615393565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613c76908790859060040161532d565b600060405180830381600087803b158015613c9057600080fd5b505af1158015613ca4573d6000803e3d6000fd5b5050505050505b50508080613cb890615463565b91505061395d565b8060005b81811015611ed6576000848483818110613ce057613ce06152df565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613d1991815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613d4592919061532d565b600060405180830381600087803b158015613d5f57600080fd5b505af1158015613d73573d6000803e3d6000fd5b50505050508080613d8390615463565b915050613cc4565b600c6020528160005260406000208181548110613da757600080fd5b90600052602060002001600091509150505481565b613dc4614130565b613dcd816141c9565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613e2b908690600401615c4c565b6020604051808303816000875af1158015613e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6e9190615611565b9050613e7b600f826142be565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613eb45750808510155b15613ebd578094505b60008092505b85831015613f1957866001613ed88585615692565b613ee29190615692565b81518110613ef257613ef26152df565b602002602001015181613f0591906155dd565b905082613f1181615463565b935050613ec3565b9694955050505050565b82516000908190831580613f375750808410155b15613f40578093505b60008467ffffffffffffffff811115613f5b57613f5b6146b6565b604051908082528060200260200182016040528015613f84578160200160208202803683370190505b509050600092505b84831015613ff257866001613fa18585615692565b613fab9190615692565b81518110613fbb57613fbb6152df565b6020026020010151818481518110613fd557613fd56152df565b602090810291909101015282613fea81615463565b935050613f8c565b61400b816000600184516140069190615692565b6142ca565b856064036140445780600182516140229190615692565b81518110614032576140326152df565b60200260200101519350505050611cef565b8060648251886140549190615d9e565b61405e9190615e0a565b8151811061406e5761406e6152df565b602002602001015193505050509392505050565b6000611cef8383614442565b60007f00000000000000000000000000000000000000000000000000000000000000001561412b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141269190615611565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff1633146141b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016120ba565b565b6000611545825490565b6000611cef838361453c565b3373ffffffffffffffffffffffffffffffffffffffff821603614248576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016120ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611cef8383614566565b81818082036142da575050505050565b60008560026142e98787615e1e565b6142f39190615e3e565b6142fd9087615ea6565b8151811061430d5761430d6152df565b602002602001015190505b81831361441c575b80868481518110614333576143336152df565b60200260200101511015614353578261434b81615ece565b935050614320565b858281518110614365576143656152df565b6020026020010151811015614386578161437e81615eff565b925050614353565b8183136144175785828151811061439f5761439f6152df565b60200260200101518684815181106143b9576143b96152df565b60200260200101518785815181106143d3576143d36152df565b602002602001018885815181106143ec576143ec6152df565b6020908102919091010191909152528261440581615ece565b935050818061441390615eff565b9250505b614318565b8185121561442f5761442f8686846142ca565b83831215611486576114868684866142ca565b6000818152600183016020526040812054801561452b576000614466600183615692565b855490915060009061447a90600190615692565b90508181146144df57600086600001828154811061449a5761449a6152df565b90600052602060002001549050808760000184815481106144bd576144bd6152df565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806144f0576144f0615f56565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611545565b6000915050611545565b5092915050565b6000826000018281548110614553576145536152df565b9060005260206000200154905092915050565b60008181526001830160205260408120546145ad57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611545565b506000611545565b5080546000825590600052602060002090810190613dcd9190614629565b828054828255906000526020600020908101928215614619579160200282015b8281111561461957825182906146099082615a46565b50916020019190600101906145f3565b5061462592915061463e565b5090565b5b80821115614625576000815560010161462a565b80821115614625576000614652828261465b565b5060010161463e565b508054614667906156a5565b6000825580601f10614677575050565b601f016020900490600052602060002090810190613dcd9190614629565b60ff81168114613dcd57600080fd5b63ffffffff81168114613dcd57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715614709576147096146b6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614756576147566146b6565b604052919050565b600067ffffffffffffffff821115614778576147786146b6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126147b557600080fd5b81356147c86147c38261475e565b61470f565b8181528460208386010111156147dd57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a03121561482f57600080fd5b873561483a81614695565b9650602088013561484a816146a4565b9550604088013561485a81614695565b9450606088013567ffffffffffffffff81111561487657600080fd5b6148828a828b016147a4565b9450506080880135614893816147fa565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146148c257600080fd5b919050565b6000806000606084860312156148dc57600080fd5b833592506148ec602085016148b0565b9150604084013590509250925092565b6000806040838503121561490f57600080fd5b82359150602083013567ffffffffffffffff81111561492d57600080fd5b614939858286016147a4565b9150509250929050565b60006020828403121561495557600080fd5b5035919050565b60005b8381101561497757818101518382015260200161495f565b50506000910152565b6000815180845261499881602086016020860161495c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611cef6020830184614980565b73ffffffffffffffffffffffffffffffffffffffff81168114613dcd57600080fd5b600080600080600080600060e0888a031215614a1a57600080fd5b873596506020880135614a2c816149dd565b95506040880135614a3c81614695565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60008060408385031215614a7757600080fd5b82359150614a87602084016148b0565b90509250929050565b600060208284031215614aa257600080fd5b8135611cef816149dd565b60008083601f840112614abf57600080fd5b50813567ffffffffffffffff811115614ad757600080fd5b6020830191508360208260051b850101111561179957600080fd5b600080600080600080600060c0888a031215614b0d57600080fd5b873567ffffffffffffffff811115614b2457600080fd5b614b308a828b01614aad565b9098509650506020880135614b4481614695565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614b8157600080fd5b505081359360208301359350604090920135919050565b60208152614bbf60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614bd8604084018263ffffffff169052565b506040830151610140806060850152614bf5610160850183614980565b91506060850151614c1660808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614c82818701836bffffffffffffffffffffffff169052565b8601519050610120614c978682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614ccf8382614980565b9695505050505050565b60008060208385031215614cec57600080fd5b823567ffffffffffffffff811115614d0357600080fd5b614d0f85828601614aad565b90969095509350505050565b60008060408385031215614d2e57600080fd5b823567ffffffffffffffff80821115614d4657600080fd5b908401906101008287031215614d5b57600080fd5b90925060208401359080821115614d7157600080fd5b50614939858286016147a4565b8215158152604060208201526000611cec6040830184614980565b60008083601f840112614dab57600080fd5b50813567ffffffffffffffff811115614dc357600080fd5b60208301915083602082850101111561179957600080fd5b60008060208385031215614dee57600080fd5b823567ffffffffffffffff811115614e0557600080fd5b614d0f85828601614d99565b6020808252825182820181905260009190848201906040850190845b81811015614e4957835183529284019291840191600101614e2d565b50909695505050505050565b600067ffffffffffffffff821115614e6f57614e6f6146b6565b5060051b60200190565b60008060408385031215614e8c57600080fd5b823567ffffffffffffffff80821115614ea457600080fd5b818501915085601f830112614eb857600080fd5b81356020614ec86147c383614e55565b82815260059290921b84018101918181019089841115614ee757600080fd5b8286015b84811015614f1f57803586811115614f035760008081fd5b614f118c86838b01016147a4565b845250918301918301614eeb565b5096505086013592505080821115614d7157600080fd5b600080600060408486031215614f4b57600080fd5b833567ffffffffffffffff811115614f6257600080fd5b614f6e86828701614aad565b9094509250506020840135614f82816146a4565b809150509250925092565b60008060408385031215614fa057600080fd5b50508035926020909101359150565b600080600060408486031215614fc457600080fd5b83359250602084013567ffffffffffffffff811115614fe257600080fd5b614fee86828701614d99565b9497909650939450505050565b6000806040838503121561500e57600080fd5b823567ffffffffffffffff8082111561502657600080fd5b615032868387016147a4565b93506020850135915080821115614d7157600080fd5b6000602080838503121561505b57600080fd5b823567ffffffffffffffff8082111561507357600080fd5b818501915085601f83011261508757600080fd5b81356150956147c382614e55565b81815260059190911b830184019084810190888311156150b457600080fd5b8585015b838110156150ec578035858111156150d05760008081fd5b6150de8b89838a01016147a4565b8452509186019186016150b8565b5098975050505050505050565b6000806040838503121561510c57600080fd5b82359150602083013561511e816147fa565b809150509250929050565b60006020828403121561513b57600080fd5b8135611cef81614695565b6000806040838503121561515957600080fd5b82359150602083013561511e816146a4565b6000806040838503121561517e57600080fd5b82359150602083013561511e81614695565b600080600080606085870312156151a657600080fd5b843567ffffffffffffffff8111156151bd57600080fd5b6151c987828801614aad565b90955093505060208501356151dd81614695565b915060408501356151ed81614695565b939692955090935050565b60008060008060008060c0878903121561521157600080fd5b863561521c816149dd565b9550602087013561522c81614695565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff808316818516818304811182151516156152ab576152ab615251565b02949350505050565b805180151581146148c257600080fd5b6000602082840312156152d657600080fd5b611cef826152b4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff810361532457615324615251565b60010192915050565b828152604060208201526000611cec6040830184614980565b600082601f83011261535757600080fd5b81516153656147c38261475e565b81815284602083860101111561537a57600080fd5b61538b82602083016020870161495c565b949350505050565b6000602082840312156153a557600080fd5b815167ffffffffffffffff8111156153bc57600080fd5b61538b84828501615346565b80516148c2816147fa565b6000602082840312156153e557600080fd5b8151611cef816147fa565b80516148c2816149dd565b6000806040838503121561540e57600080fd5b8251615419816149dd565b6020939093015192949293505050565b60006020828403121561543b57600080fd5b8151611cef816149dd565b60006020828403121561545857600080fd5b8151611cef81614695565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b5060010190565b80516148c2816146a4565b805167ffffffffffffffff811681146148c257600080fd5b6000602082840312156154d057600080fd5b815167ffffffffffffffff808211156154e857600080fd5b9083019061014082860312156154fd57600080fd5b6155056146e5565b61550e836153f0565b815261551c6020840161549b565b602082015260408301518281111561553357600080fd5b61553f87828601615346565b604083015250615551606084016153c8565b6060820152615562608084016153f0565b608082015261557360a084016154a6565b60a082015261558460c0840161549b565b60c082015261559560e084016153c8565b60e08201526101006155a88185016152b4565b9082015261012083810151838111156155c057600080fd5b6155cc88828701615346565b918301919091525095945050505050565b8082018082111561154557611545615251565b600061ffff80831681810361560757615607615251565b6001019392505050565b60006020828403121561562357600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261565f57600080fd5b83018035915067ffffffffffffffff82111561567a57600080fd5b6020019150600581901b360382131561179957600080fd5b8181038181111561154557611545615251565b600181811c908216806156b957607f821691505b6020821081036156f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000808354615706816156a5565b6001828116801561571e576001811461575157615780565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450615780565b8760005260208060002060005b858110156157775781548a82015290840190820161575e565b50505082870194505b50929695505050505050565b60008154615799816156a5565b8085526020600183811680156157b657600181146157ee5761581c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061581c565b866000528260002060005b858110156158145781548a82018601529083019084016157f9565b890184019650505b505050505092915050565b60a08152600061583a60a083018861578c565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156158ac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261589a838361578c565b94860194925060019182019101615861565b505086810360408801526158c0818b61578c565b94505050505084606084015282810360808401526158de8185614980565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561595f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261594d868351614980565b95509382019390820190600101615913565b5050858403818701525050506159758185614980565b95945050505050565b60008060006060848603121561599357600080fd5b83519250602084015191506040840151614f82816149dd565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612d8457600081815260208120601f850160051c81016020861015615a275750805b601f850160051c820191505b8181101561148657828155600101615a33565b815167ffffffffffffffff811115615a6057615a606146b6565b615a7481615a6e84546156a5565b84615a00565b602080601f831160018114615ac75760008415615a915750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611486565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615b1457888601518255948401946001909101908401615af5565b5085821015615b5057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615b7357600080fd5b825167ffffffffffffffff811115615b8a57600080fd5b8301601f81018513615b9b57600080fd5b8051615ba96147c382614e55565b81815260059190911b82018301908381019087831115615bc857600080fd5b928401925b82841015615be657835182529284019290840190615bcd565b979650505050505050565b600063ffffffff80831681810361560757615607615251565b805160208083015191908110156156f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615c6b610160850183614980565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615ca78483614980565b935060408701519150615cd2606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615d338483614980565b935060e08701519150610100818786030181880152615d528584614980565b945080880151925050610120818786030181880152615d718584614980565b94508088015192505050615d94828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615dd657615dd6615251565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615e1957615e19615ddb565b500490565b818103600083128015838313168383128216171561453557614535615251565b600082615e4d57615e4d615ddb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615ea157615ea1615251565b500590565b8082018281126000831280158216821582161715615ec657615ec6615251565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361549457615494615251565b60007f80000000000000000000000000000000000000000000000000000000000000008203615f3057615f30615251565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_useMercury\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"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\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"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\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"logNum\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_log\",\"type\":\"uint8\"}],\"name\":\"setLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useMercury\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c06040526042610140818152610100918291906200673e61016039815260200160405180608001604052806042815260200162006780604291399052620000be906016906002620003de565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee90826200055a565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526018906200012090826200055a565b503480156200012e57600080fd5b50604051620067c2380380620067c2833981016040819052620001519162000652565b82823380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd8162000333565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026091906200069e565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec9190620006cf565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c052506019805461ffff191691151561ff00191691909117905550620006f69050565b336001600160a01b038216036200038d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000429579160200282015b828111156200042957825182906200041890826200055a565b5091602001919060010190620003ff565b50620004379291506200043b565b5090565b80821115620004375760006200045282826200045c565b506001016200043b565b5080546200046a90620004cb565b6000825580601f106200047b575050565b601f0160209004906000526020600020908101906200049b91906200049e565b50565b5b808211156200043757600081556001016200049f565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004e057607f821691505b6020821081036200050157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200055557600081815260208120601f850160051c81016020861015620005305750805b601f850160051c820191505b8181101562000551578281556001016200053c565b5050505b505050565b81516001600160401b03811115620005765762000576620004b5565b6200058e81620005878454620004cb565b8462000507565b602080601f831160018114620005c65760008415620005ad5750858301515b600019600386901b1c1916600185901b17855562000551565b600085815260208120601f198616915b82811015620005f757888601518255948401946001909101908401620005d6565b5085821015620006165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200049b57600080fd5b805180151581146200064d57600080fd5b919050565b6000806000606084860312156200066857600080fd5b8351620006758162000626565b925062000685602085016200063c565b915062000695604085016200063c565b90509250925092565b60008060408385031215620006b257600080fd5b8251620006bf8162000626565b6020939093015192949293505050565b600060208284031215620006e257600080fd5b8151620006ef8162000626565b9392505050565b60805160a05160c05160e051615fe46200075a6000396000818161060201526125a3015260008181610a6801526140e40152600081816108e101528181611ffa0152613b32015260008181610e0501528181611fca0152613b070152615fe46000f3fe6080604052600436106105415760003560e01c80637b103999116102af578063af953a4a11610179578063daee1aeb116100d6578063e83ce5581161008a578063fa333dfb1161006f578063fa333dfb146110a1578063fba7ffa314611154578063fcdc1f631461118157600080fd5b8063e83ce55814611062578063f2fde38b1461108157600080fd5b8063de818253116100bb578063de81825314610fcb578063e0114adb1461101f578063e45530831461104c57600080fd5b8063daee1aeb14610f8b578063dbef701e14610fab57600080fd5b8063c41c815b1161012d578063d4c2490011610112578063d4c2490014610f2b578063d6051a7214610f4b578063da6cba4714610f6b57600080fd5b8063c41c815b14610efc578063c98f10b014610f1657600080fd5b8063b657bc9c1161015e578063b657bc9c14610e9c578063becde0e114610ebc578063c041982214610edc57600080fd5b8063af953a4a14610e67578063afb28d1f14610e8757600080fd5b8063948108f7116102275780639d385eaa116101db578063a6548248116101c0578063a654824814610df3578063a6b5947514610e27578063a72aa27e14610e4757600080fd5b80639d385eaa14610db35780639d6f1cc714610dd357600080fd5b80639ac542eb1161020c5780639ac542eb14610d2b5780639b42935414610d555780639b51fb0d14610d8257600080fd5b8063948108f714610ceb57806396cebc7c14610d0b57600080fd5b806386e330af1161027e5780638da5cb5b116102635780638da5cb5b14610c735780638fcb3fba14610c9e578063924ca57814610ccb57600080fd5b806386e330af14610c33578063873c758614610c5357600080fd5b80637b10399914610ba65780637e7a46dc14610bd35780638243444a14610bf35780638340507c14610c1357600080fd5b80634585e33b1161040b57806360457ff51161036857806373644cce1161031c578063776898c811610301578063776898c814610b5157806379ba509714610b7157806379ea994314610b8657600080fd5b806373644cce14610af75780637672130314610b2457600080fd5b8063642f6cef1161034d578063642f6cef14610a5657806369cdbadb14610a9a5780637145f11b14610ac757600080fd5b806360457ff514610a04578063636092e814610a3157600080fd5b80635147cd59116103bf57806357970e93116103a457806357970e93146109a25780635d4ee7f3146109cf5780635f17e616146109e457600080fd5b80635147cd591461095057806351c98be31461098257600080fd5b806346982093116103f057806346982093146108cf57806346e7a63e146109035780634b56a42e1461093057600080fd5b80634585e33b1461088257806345d2ec17146108a257600080fd5b8063207b6516116104b95780632a9032d31161046d578063328ffd1111610452578063328ffd11146108155780633ebe8d6c1461084257806340691db41461086257600080fd5b80632a9032d3146107a35780632b20e397146107c357600080fd5b80632636aecf1161049e5780632636aecf1461073657806328c4b57b1461075657806329e0a8411461077657600080fd5b8063207b6516146106f657806320e3dbd41461071657600080fd5b806312c55027116105105780631cdde251116104f55780631cdde251146106645780631e01043914610684578063206c32e8146106c157600080fd5b806312c55027146105f057806319d97a941461063757600080fd5b806306c1cc001461054d578063077ac6211461056f5780630b7d33e6146105a25780630fb172fb146105c257600080fd5b3661054857005b600080fd5b34801561055957600080fd5b5061056d610568366004614866565b6111ae565b005b34801561057b57600080fd5b5061058f61058a366004614919565b6113fd565b6040519081526020015b60405180910390f35b3480156105ae57600080fd5b5061056d6105bd36600461494e565b61143b565b3480156105ce57600080fd5b506105e26105dd36600461494e565b6114c9565b604051610599929190614a03565b3480156105fc57600080fd5b506106247f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff9091168152602001610599565b34801561064357600080fd5b50610657610652366004614a1e565b6114e1565b6040516105999190614a37565b34801561067057600080fd5b5061056d61067f366004614a6c565b61159e565b34801561069057600080fd5b506106a461069f366004614a1e565b6116db565b6040516bffffffffffffffffffffffff9091168152602001610599565b3480156106cd57600080fd5b506106e16106dc366004614ad1565b611770565b60408051928352602083019190915201610599565b34801561070257600080fd5b50610657610711366004614a1e565b6117f2565b34801561072257600080fd5b5061056d610731366004614afd565b61184a565b34801561074257600080fd5b5061056d610751366004614b5f565b611a14565b34801561076257600080fd5b5061058f610771366004614bd9565b611cdd565b34801561078257600080fd5b50610796610791366004614a1e565b611d48565b6040516105999190614c05565b3480156107af57600080fd5b5061056d6107be366004614d46565b611e4d565b3480156107cf57600080fd5b506011546107f09073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610599565b34801561082157600080fd5b5061058f610830366004614a1e565b60036020526000908152604090205481565b34801561084e57600080fd5b5061058f61085d366004614a1e565b611f2e565b34801561086e57600080fd5b506105e261087d366004614d88565b611f97565b34801561088e57600080fd5b5061056d61089d366004614e2d565b61249d565b3480156108ae57600080fd5b506108c26108bd366004614ad1565b6126ec565b6040516105999190614e63565b3480156108db57600080fd5b5061058f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561090f57600080fd5b5061058f61091e366004614a1e565b600a6020526000908152604090205481565b34801561093c57600080fd5b506105e261094b366004614ecb565b61275b565b34801561095c57600080fd5b5061097061096b366004614a1e565b6127af565b60405160ff9091168152602001610599565b34801561098e57600080fd5b5061056d61099d366004614f88565b612843565b3480156109ae57600080fd5b506012546107f09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109db57600080fd5b5061056d6128e7565b3480156109f057600080fd5b5061056d6109ff366004614fdf565b612a22565b348015610a1057600080fd5b5061058f610a1f366004614a1e565b60076020526000908152604090205481565b348015610a3d57600080fd5b506015546106a4906bffffffffffffffffffffffff1681565b348015610a6257600080fd5b50610a8a7f000000000000000000000000000000000000000000000000000000000000000081565b6040519015158152602001610599565b348015610aa657600080fd5b5061058f610ab5366004614a1e565b60086020526000908152604090205481565b348015610ad357600080fd5b50610a8a610ae2366004614a1e565b600b6020526000908152604090205460ff1681565b348015610b0357600080fd5b5061058f610b12366004614a1e565b6000908152600c602052604090205490565b348015610b3057600080fd5b5061058f610b3f366004614a1e565b60046020526000908152604090205481565b348015610b5d57600080fd5b50610a8a610b6c366004614a1e565b612aef565b348015610b7d57600080fd5b5061056d612b41565b348015610b9257600080fd5b506107f0610ba1366004614a1e565b612c3e565b348015610bb257600080fd5b506013546107f09073ffffffffffffffffffffffffffffffffffffffff1681565b348015610bdf57600080fd5b5061056d610bee366004615001565b612cd2565b348015610bff57600080fd5b5061056d610c0e366004615001565b612d63565b348015610c1f57600080fd5b5061056d610c2e36600461504d565b612dbd565b348015610c3f57600080fd5b5061056d610c4e36600461509a565b612ddb565b348015610c5f57600080fd5b506108c2610c6e366004614fdf565b612dee565b348015610c7f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166107f0565b348015610caa57600080fd5b5061058f610cb9366004614a1e565b60056020526000908152604090205481565b348015610cd757600080fd5b5061056d610ce6366004614fdf565b612eab565b348015610cf757600080fd5b5061056d610d0636600461514b565b6130f0565b348015610d1757600080fd5b5061056d610d2636600461517b565b613208565b348015610d3757600080fd5b50601554610970906c01000000000000000000000000900460ff1681565b348015610d6157600080fd5b5061056d610d70366004614fdf565b60009182526009602052604090912055565b348015610d8e57600080fd5b50610624610d9d366004614a1e565b600e6020526000908152604090205461ffff1681565b348015610dbf57600080fd5b506108c2610dce366004614a1e565b613412565b348015610ddf57600080fd5b50610657610dee366004614a1e565b613474565b348015610dff57600080fd5b5061058f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610e3357600080fd5b5061056d610e42366004614bd9565b613520565b348015610e5357600080fd5b5061056d610e62366004615198565b613589565b348015610e7357600080fd5b5061056d610e82366004614a1e565b613634565b348015610e9357600080fd5b506106576136ba565b348015610ea857600080fd5b506106a4610eb7366004614a1e565b6136c7565b348015610ec857600080fd5b5061056d610ed7366004614d46565b61371f565b348015610ee857600080fd5b506108c2610ef7366004614fdf565b6137b9565b348015610f0857600080fd5b50601954610a8a9060ff1681565b348015610f2257600080fd5b506106576138b6565b348015610f3757600080fd5b5061056d610f463660046151bd565b6138c3565b348015610f5757600080fd5b506106e1610f66366004614fdf565b613942565b348015610f7757600080fd5b5061056d610f863660046151e2565b6139ab565b348015610f9757600080fd5b5061056d610fa6366004614d46565b613d12565b348015610fb757600080fd5b5061058f610fc6366004614fdf565b613ddd565b348015610fd757600080fd5b5061056d610fe636600461517b565b6019805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055565b34801561102b57600080fd5b5061058f61103a366004614a1e565b60096020526000908152604090205481565b34801561105857600080fd5b5061058f60145481565b34801561106e57600080fd5b5060195461097090610100900460ff1681565b34801561108d57600080fd5b5061056d61109c366004614afd565b613e0e565b3480156110ad57600080fd5b506106576110bc36600461524a565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561116057600080fd5b5061058f61116f366004614a1e565b60066020526000908152604090205481565b34801561118d57600080fd5b5061058f61119c366004614a1e565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b3921690611294908c16886152d2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af1158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190615316565b5060008860ff1667ffffffffffffffff81111561135557611355614708565b60405190808252806020026020018201604052801561137e578160200160208202803683370190505b50905060005b8960ff168160ff1610156113f157600061139d84613e22565b905080838360ff16815181106113b5576113b5615331565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806113e981615360565b915050611384565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061142557600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e690611493908590859060040161537f565b600060405180830381600087803b1580156114ad57600080fd5b505af11580156114c1573d6000803e3d6000fd5b505050505050565b604080516000808252602082019092525b9250929050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611552573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261159891908101906153e5565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561163d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261168391908101906153e5565b6040518363ffffffff1660e01b81526004016116a092919061537f565b600060405180830381600087803b1580156116ba57600080fd5b505af11580156116ce573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115989190615425565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156117d457602002820191906000526020600020905b8154815260200190600101908083116117c0575b505050505090506117e6818251613ef0565b92509250509250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611535565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156118e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611904919061544d565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa1580156119a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119cb919061547b565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611cd2576000898983818110611a3457611a34615331565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001611a6d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611a9992919061537f565b600060405180830381600087803b158015611ab357600080fd5b505af1158015611ac7573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b619190615498565b90508060ff16600103611cbd576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611bea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c3091908101906153e5565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611c89908690859060040161537f565b600060405180830381600087803b158015611ca357600080fd5b505af1158015611cb7573d6000803e3d6000fd5b50505050505b50508080611cca906154b5565b915050611a18565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611d3e93830182828015611d3257602002820191906000526020600020905b815481526020019060010190808311611d1e575b50505050508484613f75565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611e07573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115989190810190615510565b8060005b818160ff161015611f285760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611e8f57611e8f615331565b905060200201356040518263ffffffff1660e01b8152600401611eb491815260200190565b600060405180830381600087803b158015611ece57600080fd5b505af1158015611ee2573d6000803e3d6000fd5b50505050611f1584848360ff16818110611efe57611efe615331565b90506020020135600f6140d490919063ffffffff16565b5080611f2081615360565b915050611e51565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611f8f576000858152600d6020908152604080832061ffff85168452909152902054611f7b908361562f565b915080611f8781615642565b915050611f44565b509392505050565b6000606060005a90506000611faa6140e0565b9050600085806020019051810190611fc29190615663565b6019549091507f000000000000000000000000000000000000000000000000000000000000000090610100900460ff161561201a57507f00000000000000000000000000000000000000000000000000000000000000005b8061202860c08a018a61567c565b600081811061203957612039615331565b905060200201350361243b57600061205460c08a018a61567c565b600181811061206557612065615331565b9050602002013560405160200161207e91815260200190565b60405160208183030381529060405290506000818060200190518101906120a59190615663565b9050838114612115576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f75706b6565702069647320646f6e2774206d617463680000000000000000000060448201526064015b60405180910390fd5b600061212460c08c018c61567c565b600281811061213557612135615331565b9050602002013560405160200161214e91815260200190565b60405160208183030381529060405290506000818060200190518101906121759190615663565b9050600061218660c08e018e61567c565b600381811061219757612197615331565b905060200201356040516020016121b091815260200190565b60405160208183030381529060405290506000818060200190518101906121d7919061547b565b6000868152600860205260409020549091505b805a6121f6908d6156e4565b61220290613a9861562f565b10156122435783406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556121ea565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161229a919061574a565b60405160208183030381529060405280519060200120036122bc5750836122bf565b50425b60195460ff161561236757604080516020810189905290810186905273ffffffffffffffffffffffffffffffffffffffff841660608201526017906016906018908490608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a200000000000000000000000000000000000000000000000000000000825261210c9594939291600401615879565b60165460009067ffffffffffffffff81111561238557612385614708565b6040519080825280602002602001820160405280156123b857816020015b60608152602001906001900390816123a35790505b5060408051602081018b905290810188905273ffffffffffffffffffffffffffffffffffffffff8616606082015290915060009060800160405160208183030381529060405290506001828260405160200161241592919061593c565b6040516020818303038152906040529f509f5050505050505050505050505050506114da565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f756e6578706563746564206576656e7420736967000000000000000000000000604482015260640161210c565b60005a90506000806124b184860186614ecb565b915091506000806000838060200190518101906124ce91906159d0565b60008381526005602090815260408083205460049092528220549497509295509093509091906124fc6140e0565b90508260000361251c576000868152600560205260409020819055612660565b600061252886836156e4565b6000888152600e6020908152604080832054600d835281842061ffff90911680855290835281842080548351818602810186019094528084529596509094919290919083018282801561259a57602002820191906000526020600020905b815481526020019060010190808311612586575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff1681510361261557816125d781615642565b60008b8152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000888152600d6020908152604080832061ffff9094168352928152828220805460018181018355918452828420018590558a8352600c8252928220805493840181558252902001555b60008681526006602052604081205461267a90600161562f565b60008881526006602090815260408083208490556004909152902083905590506126a48783612eab565b6040513090839089907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46126de878b84613520565b505050505050505050505050565b6000828152600d6020908152604080832061ffff8516845282529182902080548351818402810184019094528084526060939283018282801561274e57602002820191906000526020600020905b81548152602001906001019080831161273a575b5050505050905092915050565b600060606000848460405160200161277492919061593c565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa15801561281f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115989190615498565b8160005b818110156128e05730635f17e61686868481811061286757612867615331565b90506020020135856040518363ffffffff1660e01b815260040161289b92919091825263ffffffff16602082015260400190565b600060405180830381600087803b1580156128b557600080fd5b505af11580156128c9573d6000803e3d6000fd5b5050505080806128d8906154b5565b915050612847565b5050505050565b6128ef614182565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561295e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129829190615663565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156129fa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1e9190615316565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c9091528120612a5a91614607565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612ab6576000848152600d6020908152604080832061ffff851684529091528120612aa491614607565b80612aae81615642565b915050612a6f565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000818152600560205260408120548103612b0c57506001919050565b600082815260036020908152604080832054600490925290912054612b2f6140e0565b612b3991906156e4565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612bc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161210c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611598919061547b565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b590612d2c908690869086906004016159fe565b600060405180830381600087803b158015612d4657600080fd5b505af1158015612d5a573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d3590612d2c908690869086906004016159fe565b6017612dc98382615a98565b506018612dd68282615a98565b505050565b8051612a1e906016906020840190614625565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612e65573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d419190810190615bb2565b601454600083815260026020526040902054612ec790836156e4565b1115612a1e576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612f3d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f839190810190615510565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301c9190615425565b6015549091506130409082906c01000000000000000000000000900460ff166152d2565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611f28576015546130839085906bffffffffffffffffffffffff166130f0565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015613178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319c9190615316565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f790604401611493565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015613267573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526132ad9190810190615bb2565b805190915060006132bc6140e0565b905060005b828110156128e05760008482815181106132dd576132dd615331565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa15801561335d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133819190615498565b90508060ff166001036133fd578660ff166000036133cd576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a46133fd565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b5050808061340a906154b5565b9150506132c1565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561346857602002820191906000526020600020905b815481526020019060010190808311613454575b50505050509050919050565b6016818154811061348457600080fd5b90600052602060002001600091509050805461349f906156f7565b80601f01602080910402602001604051908101604052809291908181526020018280546134cb906156f7565b80156135185780601f106134ed57610100808354040283529160200191613518565b820191906000526020600020905b8154815290600101906020018083116134fb57829003601f168201915b505050505081565b6000838152600760205260409020545b805a61353c90856156e4565b6135489061271061562f565b1015611f285781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055613530565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561360157600080fd5b505af1158015613615573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156136a657600080fd5b505af11580156128e0573d6000803e3d6000fd5b6017805461349f906156f7565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c9060240161172f565b8060005b818163ffffffff161015611f28573063af953a4a858563ffffffff851681811061374f5761374f615331565b905060200201356040518263ffffffff1660e01b815260040161377491815260200190565b600060405180830381600087803b15801561378e57600080fd5b505af11580156137a2573d6000803e3d6000fd5b5050505080806137b190615c43565b915050613723565b606060006137c7600f614205565b9050808410613802576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036138175761381484826156e4565b92505b60008367ffffffffffffffff81111561383257613832614708565b60405190808252806020026020018201604052801561385b578160200160208202803683370190505b50905060005b848110156138ad5761387e613876828861562f565b600f9061420f565b82828151811061389057613890615331565b6020908102919091010152806138a5816154b5565b915050613861565b50949350505050565b6018805461349f906156f7565b60006138cd6140e0565b90508160ff1660000361390e576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561399a57602002820191906000526020600020905b815481526020019060010190808311613986575b505050505090506117e68185613ef0565b8260005b818110156114c15760008686838181106139cb576139cb615331565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613a0491815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613a3092919061537f565b600060405180830381600087803b158015613a4a57600080fd5b505af1158015613a5e573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613ad4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af89190615498565b90508060ff16600103613cfd577f000000000000000000000000000000000000000000000000000000000000000060ff871615613b5257507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb30898588604051602001613b8691815260200190565b604051602081830303815290604052613b9e90615c5c565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa158015613c29573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052613c6f91908101906153e5565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590613cc8908790859060040161537f565b600060405180830381600087803b158015613ce257600080fd5b505af1158015613cf6573d6000803e3d6000fd5b5050505050505b50508080613d0a906154b5565b9150506139af565b8060005b81811015611f28576000848483818110613d3257613d32615331565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc8283604051602001613d6b91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613d9792919061537f565b600060405180830381600087803b158015613db157600080fd5b505af1158015613dc5573d6000803e3d6000fd5b50505050508080613dd5906154b5565b915050613d16565b600c6020528160005260406000208181548110613df957600080fd5b90600052602060002001600091509150505481565b613e16614182565b613e1f8161421b565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613e7d908690600401615c9e565b6020604051808303816000875af1158015613e9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ec09190615663565b9050613ecd600f82614310565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613f065750808510155b15613f0f578094505b60008092505b85831015613f6b57866001613f2a85856156e4565b613f3491906156e4565b81518110613f4457613f44615331565b602002602001015181613f57919061562f565b905082613f63816154b5565b935050613f15565b9694955050505050565b82516000908190831580613f895750808410155b15613f92578093505b60008467ffffffffffffffff811115613fad57613fad614708565b604051908082528060200260200182016040528015613fd6578160200160208202803683370190505b509050600092505b8483101561404457866001613ff385856156e4565b613ffd91906156e4565b8151811061400d5761400d615331565b602002602001015181848151811061402757614027615331565b60209081029190910101528261403c816154b5565b935050613fde565b61405d8160006001845161405891906156e4565b61431c565b8560640361409657806001825161407491906156e4565b8151811061408457614084615331565b60200260200101519350505050611d41565b8060648251886140a69190615df0565b6140b09190615e5c565b815181106140c0576140c0615331565b602002602001015193505050509392505050565b6000611d418383614494565b60007f00000000000000000000000000000000000000000000000000000000000000001561417d57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614154573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141789190615663565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314614203576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161210c565b565b6000611598825490565b6000611d41838361458e565b3373ffffffffffffffffffffffffffffffffffffffff82160361429a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161210c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611d4183836145b8565b818180820361432c575050505050565b600085600261433b8787615e70565b6143459190615e90565b61434f9087615ef8565b8151811061435f5761435f615331565b602002602001015190505b81831361446e575b8086848151811061438557614385615331565b602002602001015110156143a5578261439d81615f20565b935050614372565b8582815181106143b7576143b7615331565b60200260200101518110156143d857816143d081615f51565b9250506143a5565b818313614469578582815181106143f1576143f1615331565b602002602001015186848151811061440b5761440b615331565b602002602001015187858151811061442557614425615331565b6020026020010188858151811061443e5761443e615331565b6020908102919091010191909152528261445781615f20565b935050818061446590615f51565b9250505b61436a565b818512156144815761448186868461431c565b838312156114c1576114c186848661431c565b6000818152600183016020526040812054801561457d5760006144b86001836156e4565b85549091506000906144cc906001906156e4565b90508181146145315760008660000182815481106144ec576144ec615331565b906000526020600020015490508087600001848154811061450f5761450f615331565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061454257614542615fa8565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611598565b6000915050611598565b5092915050565b60008260000182815481106145a5576145a5615331565b9060005260206000200154905092915050565b60008181526001830160205260408120546145ff57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611598565b506000611598565b5080546000825590600052602060002090810190613e1f919061467b565b82805482825590600052602060002090810192821561466b579160200282015b8281111561466b578251829061465b9082615a98565b5091602001919060010190614645565b50614677929150614690565b5090565b5b80821115614677576000815560010161467c565b808211156146775760006146a482826146ad565b50600101614690565b5080546146b9906156f7565b6000825580601f106146c9575050565b601f016020900490600052602060002090810190613e1f919061467b565b60ff81168114613e1f57600080fd5b63ffffffff81168114613e1f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561475b5761475b614708565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156147a8576147a8614708565b604052919050565b600067ffffffffffffffff8211156147ca576147ca614708565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261480757600080fd5b813561481a614815826147b0565b614761565b81815284602083860101111561482f57600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613e1f57600080fd5b600080600080600080600060e0888a03121561488157600080fd5b873561488c816146e7565b9650602088013561489c816146f6565b955060408801356148ac816146e7565b9450606088013567ffffffffffffffff8111156148c857600080fd5b6148d48a828b016147f6565b94505060808801356148e58161484c565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461491457600080fd5b919050565b60008060006060848603121561492e57600080fd5b8335925061493e60208501614902565b9150604084013590509250925092565b6000806040838503121561496157600080fd5b82359150602083013567ffffffffffffffff81111561497f57600080fd5b61498b858286016147f6565b9150509250929050565b60005b838110156149b0578181015183820152602001614998565b50506000910152565b600081518084526149d1816020860160208601614995565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000611d3e60408301846149b9565b600060208284031215614a3057600080fd5b5035919050565b602081526000611d4160208301846149b9565b73ffffffffffffffffffffffffffffffffffffffff81168114613e1f57600080fd5b600080600080600080600060e0888a031215614a8757600080fd5b873596506020880135614a9981614a4a565b95506040880135614aa9816146e7565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60008060408385031215614ae457600080fd5b82359150614af460208401614902565b90509250929050565b600060208284031215614b0f57600080fd5b8135611d4181614a4a565b60008083601f840112614b2c57600080fd5b50813567ffffffffffffffff811115614b4457600080fd5b6020830191508360208260051b85010111156114da57600080fd5b600080600080600080600060c0888a031215614b7a57600080fd5b873567ffffffffffffffff811115614b9157600080fd5b614b9d8a828b01614b1a565b9098509650506020880135614bb1816146e7565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b600080600060608486031215614bee57600080fd5b505081359360208301359350604090920135919050565b60208152614c2c60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614c45604084018263ffffffff169052565b506040830151610140806060850152614c626101608501836149b9565b91506060850151614c8360808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614cef818701836bffffffffffffffffffffffff169052565b8601519050610120614d048682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050614d3c83826149b9565b9695505050505050565b60008060208385031215614d5957600080fd5b823567ffffffffffffffff811115614d7057600080fd5b614d7c85828601614b1a565b90969095509350505050565b60008060408385031215614d9b57600080fd5b823567ffffffffffffffff80821115614db357600080fd5b908401906101008287031215614dc857600080fd5b90925060208401359080821115614dde57600080fd5b5061498b858286016147f6565b60008083601f840112614dfd57600080fd5b50813567ffffffffffffffff811115614e1557600080fd5b6020830191508360208285010111156114da57600080fd5b60008060208385031215614e4057600080fd5b823567ffffffffffffffff811115614e5757600080fd5b614d7c85828601614deb565b6020808252825182820181905260009190848201906040850190845b81811015614e9b57835183529284019291840191600101614e7f565b50909695505050505050565b600067ffffffffffffffff821115614ec157614ec1614708565b5060051b60200190565b60008060408385031215614ede57600080fd5b823567ffffffffffffffff80821115614ef657600080fd5b818501915085601f830112614f0a57600080fd5b81356020614f1a61481583614ea7565b82815260059290921b84018101918181019089841115614f3957600080fd5b8286015b84811015614f7157803586811115614f555760008081fd5b614f638c86838b01016147f6565b845250918301918301614f3d565b5096505086013592505080821115614dde57600080fd5b600080600060408486031215614f9d57600080fd5b833567ffffffffffffffff811115614fb457600080fd5b614fc086828701614b1a565b9094509250506020840135614fd4816146f6565b809150509250925092565b60008060408385031215614ff257600080fd5b50508035926020909101359150565b60008060006040848603121561501657600080fd5b83359250602084013567ffffffffffffffff81111561503457600080fd5b61504086828701614deb565b9497909650939450505050565b6000806040838503121561506057600080fd5b823567ffffffffffffffff8082111561507857600080fd5b615084868387016147f6565b93506020850135915080821115614dde57600080fd5b600060208083850312156150ad57600080fd5b823567ffffffffffffffff808211156150c557600080fd5b818501915085601f8301126150d957600080fd5b81356150e761481582614ea7565b81815260059190911b8301840190848101908883111561510657600080fd5b8585015b8381101561513e578035858111156151225760008081fd5b6151308b89838a01016147f6565b84525091860191860161510a565b5098975050505050505050565b6000806040838503121561515e57600080fd5b8235915060208301356151708161484c565b809150509250929050565b60006020828403121561518d57600080fd5b8135611d41816146e7565b600080604083850312156151ab57600080fd5b823591506020830135615170816146f6565b600080604083850312156151d057600080fd5b823591506020830135615170816146e7565b600080600080606085870312156151f857600080fd5b843567ffffffffffffffff81111561520f57600080fd5b61521b87828801614b1a565b909550935050602085013561522f816146e7565b9150604085013561523f816146e7565b939692955090935050565b60008060008060008060c0878903121561526357600080fd5b863561526e81614a4a565b9550602087013561527e816146e7565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff808316818516818304811182151516156152fd576152fd6152a3565b02949350505050565b8051801515811461491457600080fd5b60006020828403121561532857600080fd5b611d4182615306565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103615376576153766152a3565b60010192915050565b828152604060208201526000611d3e60408301846149b9565b600082601f8301126153a957600080fd5b81516153b7614815826147b0565b8181528460208386010111156153cc57600080fd5b6153dd826020830160208701614995565b949350505050565b6000602082840312156153f757600080fd5b815167ffffffffffffffff81111561540e57600080fd5b6153dd84828501615398565b80516149148161484c565b60006020828403121561543757600080fd5b8151611d418161484c565b805161491481614a4a565b6000806040838503121561546057600080fd5b825161546b81614a4a565b6020939093015192949293505050565b60006020828403121561548d57600080fd5b8151611d4181614a4a565b6000602082840312156154aa57600080fd5b8151611d41816146e7565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036154e6576154e66152a3565b5060010190565b8051614914816146f6565b805167ffffffffffffffff8116811461491457600080fd5b60006020828403121561552257600080fd5b815167ffffffffffffffff8082111561553a57600080fd5b90830190610140828603121561554f57600080fd5b615557614737565b61556083615442565b815261556e602084016154ed565b602082015260408301518281111561558557600080fd5b61559187828601615398565b6040830152506155a36060840161541a565b60608201526155b460808401615442565b60808201526155c560a084016154f8565b60a08201526155d660c084016154ed565b60c08201526155e760e0840161541a565b60e08201526101006155fa818501615306565b90820152610120838101518381111561561257600080fd5b61561e88828701615398565b918301919091525095945050505050565b80820180821115611598576115986152a3565b600061ffff808316818103615659576156596152a3565b6001019392505050565b60006020828403121561567557600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126156b157600080fd5b83018035915067ffffffffffffffff8211156156cc57600080fd5b6020019150600581901b36038213156114da57600080fd5b81810381811115611598576115986152a3565b600181811c9082168061570b57607f821691505b602082108103615744577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000808354615758816156f7565b6001828116801561577057600181146157a3576157d2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506157d2565b8760005260208060002060005b858110156157c95781548a8201529084019082016157b0565b50505082870194505b50929695505050505050565b600081546157eb816156f7565b80855260206001838116801561580857600181146158405761586e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061586e565b866000528260002060005b858110156158665781548a820186015290830190840161584b565b890184019650505b505050505092915050565b60a08152600061588c60a08301886157de565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156158fe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526158ec83836157de565b948601949250600191820191016158b3565b50508681036040880152615912818b6157de565b945050505050846060840152828103608084015261593081856149b9565b98975050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156159b1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261599f8683516149b9565b95509382019390820190600101615965565b5050858403818701525050506159c781856149b9565b95945050505050565b6000806000606084860312156159e557600080fd5b83519250602084015191506040840151614fd481614a4a565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f821115612dd657600081815260208120601f850160051c81016020861015615a795750805b601f850160051c820191505b818110156114c157828155600101615a85565b815167ffffffffffffffff811115615ab257615ab2614708565b615ac681615ac084546156f7565b84615a52565b602080601f831160018114615b195760008415615ae35750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114c1565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615b6657888601518255948401946001909101908401615b47565b5085821015615ba257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808385031215615bc557600080fd5b825167ffffffffffffffff811115615bdc57600080fd5b8301601f81018513615bed57600080fd5b8051615bfb61481582614ea7565b81815260059190911b82018301908381019087831115615c1a57600080fd5b928401925b82841015615c3857835182529284019290840190615c1f565b979650505050505050565b600063ffffffff808316818103615659576156596152a3565b80516020808301519190811015615744577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615cbd6101608501836149b9565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080868503016040870152615cf984836149b9565b935060408701519150615d24606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e0870152615d8584836149b9565b935060e08701519150610100818786030181880152615da485846149b9565b945080880151925050610120818786030181880152615dc385846149b9565b94508088015192505050615de6828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615e2857615e286152a3565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615e6b57615e6b615e2d565b500490565b8181036000831280158383131683831282161715614587576145876152a3565b600082615e9f57615e9f615e2d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615ef357615ef36152a3565b500590565b8082018281126000831280158216821582161715615f1857615f186152a3565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036154e6576154e66152a3565b60007f80000000000000000000000000000000000000000000000000000000000000008203615f8257615f826152a3565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadLogTriggerUpkeepABI = VerifiableLoadLogTriggerUpkeepMetaData.ABI @@ -306,6 +306,36 @@ func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepCallerSessi return _VerifiableLoadLogTriggerUpkeep.Contract.CheckCallback(&_VerifiableLoadLogTriggerUpkeep.CallOpts, values, extraData) } +func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _VerifiableLoadLogTriggerUpkeep.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _VerifiableLoadLogTriggerUpkeep.Contract.CheckErrorHandler(&_VerifiableLoadLogTriggerUpkeep.CallOpts, errCode, extraData) +} + +func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _VerifiableLoadLogTriggerUpkeep.Contract.CheckErrorHandler(&_VerifiableLoadLogTriggerUpkeep.CallOpts, errCode, extraData) +} + func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepCaller) CheckGasToBurns(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { var out []interface{} err := _VerifiableLoadLogTriggerUpkeep.contract.Call(opts, &out, "checkGasToBurns", arg0) @@ -2295,6 +2325,11 @@ func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeepFilterer) P return event, nil } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} + func (_VerifiableLoadLogTriggerUpkeep *VerifiableLoadLogTriggerUpkeep) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _VerifiableLoadLogTriggerUpkeep.abi.Events["LogEmitted"].ID: @@ -2348,6 +2383,10 @@ type VerifiableLoadLogTriggerUpkeepInterface interface { CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + CheckGasToBurns(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) Counters(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) diff --git a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go index fc39ffb366b..62e3d23bda4 100644 --- a/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go +++ b/core/gethwrappers/generated/verifiable_load_streams_lookup_upkeep_wrapper/verifiable_load_streams_lookup_upkeep_wrapper.go @@ -44,8 +44,8 @@ type KeeperRegistryBase21UpkeepInfo struct { } var VerifiableLoadStreamsLookupUpkeepMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"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\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c0604052604261014081815261010091829190620061d161016039815260200160405180608001604052806042815260200162006213604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b506040516200625538038062006255833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e051615abb62000716600039600081816105680152611f7a0152600081816109bc0152613ca701526000818161082701526136f5015260008181610d7901526136ca0152615abb6000f3fe6080604052600436106104d55760003560e01c806379ea994311610279578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610f88578063fba7ffa31461103b578063fcdc1f631461106857600080fd5b8063e455308314610f52578063f2fde38b14610f6857600080fd5b8063daee1aeb116100bb578063daee1aeb14610ee5578063dbef701e14610f05578063e0114adb14610f2557600080fd5b8063d6051a7214610ea5578063da6cba4714610ec557600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e50578063c98f10b014610e70578063d4c2490014610e8557600080fd5b8063b657bc9c14610e10578063becde0e114610e3057600080fd5b8063a6b5947514610d9b578063a72aa27e14610dbb578063af953a4a14610ddb578063afb28d1f14610dfb57600080fd5b8063924ca578116101f15780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d275780639d6f1cc714610d47578063a654824814610d6757600080fd5b80639b42935414610cc95780639b51fb0d14610cf657600080fd5b8063924ca57814610c3f578063948108f714610c5f57806396cebc7c14610c7f5780639ac542eb14610c9f57600080fd5b80638340507c11610248578063873c75861161022d578063873c758614610bc75780638da5cb5b14610be75780638fcb3fba14610c1257600080fd5b80638340507c14610b8757806386e330af14610ba757600080fd5b806379ea994314610afa5780637b10399914610b1a5780637e7a46dc14610b475780638243444a14610b6757600080fd5b806345d2ec17116103ba57806360457ff5116103325780637145f11b116102e657806376721303116102cb5780637672130314610a98578063776898c814610ac557806379ba509714610ae557600080fd5b80637145f11b14610a3b57806373644cce14610a6b57600080fd5b8063642f6cef11610317578063642f6cef146109aa57806369cdbadb146109ee5780636e04ff0d14610a1b57600080fd5b806360457ff514610958578063636092e81461098557600080fd5b80635147cd591161038957806357970e931161036e57806357970e93146108f65780635d4ee7f3146109235780635f17e6161461093857600080fd5b80635147cd59146108a457806351c98be3146108d657600080fd5b806345d2ec17146107e8578063469820931461081557806346e7a63e146108495780634b56a42e1461087657600080fd5b806320e3dbd41161044d5780632a9032d31161041c578063328ffd1111610401578063328ffd111461077b5780633ebe8d6c146107a85780634585e33b146107c857600080fd5b80632a9032d3146107095780632b20e3971461072957600080fd5b806320e3dbd41461067c5780632636aecf1461069c57806328c4b57b146106bc57806329e0a841146106dc57600080fd5b806319d97a94116104a45780631e010439116104895780631e010439146105ea578063206c32e814610627578063207b65161461065c57600080fd5b806319d97a941461059d5780631cdde251146105ca57600080fd5b806306c1cc00146104e1578063077ac621146105035780630b7d33e61461053657806312c550271461055657600080fd5b366104dc57005b600080fd5b3480156104ed57600080fd5b506105016104fc366004614429565b611095565b005b34801561050f57600080fd5b5061052361051e3660046144dc565b6112e4565b6040519081526020015b60405180910390f35b34801561054257600080fd5b50610501610551366004614511565b611322565b34801561056257600080fd5b5061058a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161052d565b3480156105a957600080fd5b506105bd6105b8366004614558565b6113b0565b60405161052d91906145df565b3480156105d657600080fd5b506105016105e5366004614614565b61146d565b3480156105f657600080fd5b5061060a610605366004614558565b6115aa565b6040516bffffffffffffffffffffffff909116815260200161052d565b34801561063357600080fd5b50610647610642366004614679565b61163f565b6040805192835260208301919091520161052d565b34801561066857600080fd5b506105bd610677366004614558565b6116c2565b34801561068857600080fd5b506105016106973660046146a5565b61171a565b3480156106a857600080fd5b506105016106b7366004614707565b6118e4565b3480156106c857600080fd5b506105236106d7366004614781565b611bad565b3480156106e857600080fd5b506106fc6106f7366004614558565b611c18565b60405161052d91906147ad565b34801561071557600080fd5b506105016107243660046148ee565b611d1d565b34801561073557600080fd5b506011546107569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161052d565b34801561078757600080fd5b50610523610796366004614558565b60036020526000908152604090205481565b3480156107b457600080fd5b506105236107c3366004614558565b611dfe565b3480156107d457600080fd5b506105016107e3366004614972565b611e67565b3480156107f457600080fd5b50610808610803366004614679565b612086565b60405161052d91906149a8565b34801561082157600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b34801561085557600080fd5b50610523610864366004614558565b600a6020526000908152604090205481565b34801561088257600080fd5b50610896610891366004614a10565b6120f5565b60405161052d929190614ada565b3480156108b057600080fd5b506108c46108bf366004614558565b612149565b60405160ff909116815260200161052d565b3480156108e257600080fd5b506105016108f1366004614af5565b6121dd565b34801561090257600080fd5b506012546107569073ffffffffffffffffffffffffffffffffffffffff1681565b34801561092f57600080fd5b50610501612281565b34801561094457600080fd5b50610501610953366004614b4c565b6123bc565b34801561096457600080fd5b50610523610973366004614558565b60076020526000908152604090205481565b34801561099157600080fd5b5060155461060a906bffffffffffffffffffffffff1681565b3480156109b657600080fd5b506109de7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161052d565b3480156109fa57600080fd5b50610523610a09366004614558565b60086020526000908152604090205481565b348015610a2757600080fd5b50610896610a36366004614972565b612489565b348015610a4757600080fd5b506109de610a56366004614558565b600b6020526000908152604090205460ff1681565b348015610a7757600080fd5b50610523610a86366004614558565b6000908152600c602052604090205490565b348015610aa457600080fd5b50610523610ab3366004614558565b60046020526000908152604090205481565b348015610ad157600080fd5b506109de610ae0366004614558565b6126b2565b348015610af157600080fd5b50610501612704565b348015610b0657600080fd5b50610756610b15366004614558565b612801565b348015610b2657600080fd5b506013546107569073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b5357600080fd5b50610501610b62366004614b6e565b612895565b348015610b7357600080fd5b50610501610b82366004614b6e565b612926565b348015610b9357600080fd5b50610501610ba2366004614bba565b612980565b348015610bb357600080fd5b50610501610bc2366004614c07565b61299e565b348015610bd357600080fd5b50610808610be2366004614b4c565b6129b1565b348015610bf357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610756565b348015610c1e57600080fd5b50610523610c2d366004614558565b60056020526000908152604090205481565b348015610c4b57600080fd5b50610501610c5a366004614b4c565b612a6e565b348015610c6b57600080fd5b50610501610c7a366004614cb8565b612cb3565b348015610c8b57600080fd5b50610501610c9a366004614ce8565b612dcb565b348015610cab57600080fd5b506015546108c4906c01000000000000000000000000900460ff1681565b348015610cd557600080fd5b50610501610ce4366004614b4c565b60009182526009602052604090912055565b348015610d0257600080fd5b5061058a610d11366004614558565b600e6020526000908152604090205461ffff1681565b348015610d3357600080fd5b50610808610d42366004614558565b612fd5565b348015610d5357600080fd5b506105bd610d62366004614558565b613037565b348015610d7357600080fd5b506105237f000000000000000000000000000000000000000000000000000000000000000081565b348015610da757600080fd5b50610501610db6366004614781565b6130e3565b348015610dc757600080fd5b50610501610dd6366004614d05565b61314c565b348015610de757600080fd5b50610501610df6366004614558565b6131f7565b348015610e0757600080fd5b506105bd61327d565b348015610e1c57600080fd5b5061060a610e2b366004614558565b61328a565b348015610e3c57600080fd5b50610501610e4b3660046148ee565b6132e2565b348015610e5c57600080fd5b50610808610e6b366004614b4c565b61337c565b348015610e7c57600080fd5b506105bd613479565b348015610e9157600080fd5b50610501610ea0366004614d2a565b613486565b348015610eb157600080fd5b50610647610ec0366004614b4c565b613505565b348015610ed157600080fd5b50610501610ee0366004614d4f565b61356e565b348015610ef157600080fd5b50610501610f003660046148ee565b6138d5565b348015610f1157600080fd5b50610523610f20366004614b4c565b6139a0565b348015610f3157600080fd5b50610523610f40366004614558565b60096020526000908152604090205481565b348015610f5e57600080fd5b5061052360145481565b348015610f7457600080fd5b50610501610f833660046146a5565b6139d1565b348015610f9457600080fd5b506105bd610fa3366004614db7565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561104757600080fd5b50610523611056366004614558565b60066020526000908152604090205481565b34801561107457600080fd5b50610523611083366004614558565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b392169061117b908c1688614e3f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af11580156111f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121d9190614e83565b5060008860ff1667ffffffffffffffff81111561123c5761123c6142cb565b604051908082528060200260200182016040528015611265578160200160208202803683370190505b50905060005b8960ff168160ff1610156112d8576000611284846139e5565b905080838360ff168151811061129c5761129c614e9e565b602090810291909101810191909152600091825260088152604080832088905560079091529020849055806112d081614ecd565b91505061126b565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061130c57600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e69061137a9085908590600401614eec565b600060405180830381600087803b15801561139457600080fd5b505af11580156113a8573d6000803e3d6000fd5b505050505050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611421573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114679190810190614f52565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561150c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115529190810190614f52565b6040518363ffffffff1660e01b815260040161156f929190614eec565b600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614f92565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116a357602002820191906000526020600020905b81548152602001906001019080831161168f575b505050505090506116b5818251613ab3565b92509250505b9250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611404565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190614fba565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190614fe8565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611ba257600089898381811061190457611904614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161193d91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611969929190614eec565b600060405180830381600087803b15801561198357600080fd5b505af1158015611997573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a319190615005565b90508060ff16600103611b8d576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611aba573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b009190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611b599086908590600401614eec565b600060405180830381600087803b158015611b7357600080fd5b505af1158015611b87573d6000803e3d6000fd5b50505050505b50508080611b9a90615022565b9150506118e8565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c0e93830182828015611c0257602002820191906000526020600020905b815481526020019060010190808311611bee575b50505050508484613b38565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611cd7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611467919081019061507d565b8060005b818160ff161015611df85760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611d5f57611d5f614e9e565b905060200201356040518263ffffffff1660e01b8152600401611d8491815260200190565b600060405180830381600087803b158015611d9e57600080fd5b505af1158015611db2573d6000803e3d6000fd5b50505050611de584848360ff16818110611dce57611dce614e9e565b90506020020135600f613c9790919063ffffffff16565b5080611df081614ecd565b915050611d21565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611e5f576000858152600d6020908152604080832061ffff85168452909152902054611e4b908361519c565b915080611e57816151af565b915050611e14565b509392505050565b60005a9050600080611e7b84860186614a10565b91509150600081806020019051810190611e9591906151d0565b60008181526005602090815260408083205460049092528220549293509190611ebc613ca3565b905082600003611edc576000848152600560205260409020819055612037565b600084815260036020526040812054611ef584846151e9565b611eff91906151e9565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611f7157602002820191906000526020600020905b815481526020019060010190808311611f5d575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff16815103611fec5781611fae816151af565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b60008481526006602052604081205461205190600161519c565b600086815260066020908152604080832084905560049091529020839055905061207b8583612a6e565b6112d88589846130e3565b6000828152600d6020908152604080832061ffff851684528252918290208054835181840281018401909452808452606093928301828280156120e857602002820191906000526020600020905b8154815260200190600101908083116120d4575b5050505050905092915050565b600060606000848460405160200161210e9291906151fc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190615005565b8160005b8181101561227a5730635f17e61686868481811061220157612201614e9e565b90506020020135856040518363ffffffff1660e01b815260040161223592919091825263ffffffff16602082015260400190565b600060405180830381600087803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50505050808061227290615022565b9150506121e1565b5050505050565b612289613d45565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156122f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231c91906151d0565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015612394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b89190614e83565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206123f4916141ca565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff1611612450576000848152600d6020908152604080832061ffff85168452909152812061243e916141ca565b80612448816151af565b915050612409565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124a085870187614558565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff8111156124d9576124d96142cb565b6040519080825280601f01601f191660200182016040528015612503576020820181803683370190505b50604051602001612515929190614eec565b60405160208183030381529060405290506000612530613ca3565b9050600061253d866126b2565b90505b835a61254c90896151e9565b6125589061271061519c565b10156125995781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612540565b806125b15760008398509850505050505050506116bb565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161260891906152e3565b604051602081830303815290604052805190602001200361262a57508161262d565b50425b601760166018838a60405160200161264791815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526126a99594939291600401615412565b60405180910390fd5b60008181526005602052604081205481036126cf57506001919050565b6000828152600360209081526040808320546004909252909120546126f2613ca3565b6126fc91906151e9565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016126a9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa158015612871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190614fe8565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b5906128ef908690869086906004016154d5565b600060405180830381600087803b15801561290957600080fd5b505af115801561291d573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d35906128ef908690869086906004016154d5565b601761298c838261556f565b506018612999828261556f565b505050565b80516123b89060169060208401906141e8565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612a28573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c119190810190615689565b601454600083815260026020526040902054612a8a90836151e9565b11156123b8576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b46919081019061507d565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdf9190614f92565b601554909150612c039082906c01000000000000000000000000900460ff16614e3f565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611df857601554612c469085906bffffffffffffffffffffffff16612cb3565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190614e83565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f79060440161137a565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612e2a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612e709190810190615689565b80519091506000612e7f613ca3565b905060005b8281101561227a576000848281518110612ea057612ea0614e9e565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f449190615005565b90508060ff16600103612fc0578660ff16600003612f90576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4612fc0565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b50508080612fcd90615022565b915050612e84565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561302b57602002820191906000526020600020905b815481526020019060010190808311613017575b50505050509050919050565b6016818154811061304757600080fd5b90600052602060002001600091509050805461306290615290565b80601f016020809104026020016040519081016040528092919081815260200182805461308e90615290565b80156130db5780601f106130b0576101008083540402835291602001916130db565b820191906000526020600020905b8154815290600101906020018083116130be57829003601f168201915b505050505081565b6000838152600760205260409020545b805a6130ff90856151e9565b61310b9061271061519c565b1015611df85781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556130f3565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b1580156131c457600080fd5b505af11580156131d8573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b15801561326957600080fd5b505af115801561227a573d6000803e3d6000fd5b6017805461306290615290565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c906024016115fe565b8060005b818163ffffffff161015611df8573063af953a4a858563ffffffff851681811061331257613312614e9e565b905060200201356040518263ffffffff1660e01b815260040161333791815260200190565b600060405180830381600087803b15801561335157600080fd5b505af1158015613365573d6000803e3d6000fd5b5050505080806133749061571a565b9150506132e6565b6060600061338a600f613dc8565b90508084106133c5576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036133da576133d784826151e9565b92505b60008367ffffffffffffffff8111156133f5576133f56142cb565b60405190808252806020026020018201604052801561341e578160200160208202803683370190505b50905060005b8481101561347057613441613439828861519c565b600f90613dd2565b82828151811061345357613453614e9e565b60209081029190910101528061346881615022565b915050613424565b50949350505050565b6018805461306290615290565b6000613490613ca3565b90508160ff166000036134d1576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c6020908152604080832080548251818502810185019093528083528493849392919083018282801561355d57602002820191906000526020600020905b815481526020019060010190808311613549575b505050505090506116b58185613ab3565b8260005b818110156113a857600086868381811061358e5761358e614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc82836040516020016135c791815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016135f3929190614eec565b600060405180830381600087803b15801561360d57600080fd5b505af1158015613621573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015613697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bb9190615005565b90508060ff166001036138c0577f000000000000000000000000000000000000000000000000000000000000000060ff87161561371557507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb3089858860405160200161374991815260200190565b60405160208183030381529060405261376190615733565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa1580156137ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526138329190810190614f52565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d359061388b9087908590600401614eec565b600060405180830381600087803b1580156138a557600080fd5b505af11580156138b9573d6000803e3d6000fd5b5050505050505b505080806138cd90615022565b915050613572565b8060005b81811015611df85760008484838181106138f5576138f5614e9e565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161392e91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161395a929190614eec565b600060405180830381600087803b15801561397457600080fd5b505af1158015613988573d6000803e3d6000fd5b5050505050808061399890615022565b9150506138d9565b600c60205281600052604060002081815481106139bc57600080fd5b90600052602060002001600091509150505481565b6139d9613d45565b6139e281613dde565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613a40908690600401615775565b6020604051808303816000875af1158015613a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8391906151d0565b9050613a90600f82613ed3565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613ac95750808510155b15613ad2578094505b60008092505b85831015613b2e57866001613aed85856151e9565b613af791906151e9565b81518110613b0757613b07614e9e565b602002602001015181613b1a919061519c565b905082613b2681615022565b935050613ad8565b9694955050505050565b82516000908190831580613b4c5750808410155b15613b55578093505b60008467ffffffffffffffff811115613b7057613b706142cb565b604051908082528060200260200182016040528015613b99578160200160208202803683370190505b509050600092505b84831015613c0757866001613bb685856151e9565b613bc091906151e9565b81518110613bd057613bd0614e9e565b6020026020010151818481518110613bea57613bea614e9e565b602090810291909101015282613bff81615022565b935050613ba1565b613c2081600060018451613c1b91906151e9565b613edf565b85606403613c59578060018251613c3791906151e9565b81518110613c4757613c47614e9e565b60200260200101519350505050611c11565b806064825188613c6991906158c7565b613c739190615933565b81518110613c8357613c83614e9e565b602002602001015193505050509392505050565b6000611c118383614057565b60007f000000000000000000000000000000000000000000000000000000000000000015613d4057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d3b91906151d0565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613dc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016126a9565b565b6000611467825490565b6000611c118383614151565b3373ffffffffffffffffffffffffffffffffffffffff821603613e5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016126a9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c11838361417b565b8181808203613eef575050505050565b6000856002613efe8787615947565b613f089190615967565b613f1290876159cf565b81518110613f2257613f22614e9e565b602002602001015190505b818313614031575b80868481518110613f4857613f48614e9e565b60200260200101511015613f685782613f60816159f7565b935050613f35565b858281518110613f7a57613f7a614e9e565b6020026020010151811015613f9b5781613f9381615a28565b925050613f68565b81831361402c57858281518110613fb457613fb4614e9e565b6020026020010151868481518110613fce57613fce614e9e565b6020026020010151878581518110613fe857613fe8614e9e565b6020026020010188858151811061400157614001614e9e565b6020908102919091010191909152528261401a816159f7565b935050818061402890615a28565b9250505b613f2d565b8185121561404457614044868684613edf565b838312156113a8576113a8868486613edf565b6000818152600183016020526040812054801561414057600061407b6001836151e9565b855490915060009061408f906001906151e9565b90508181146140f45760008660000182815481106140af576140af614e9e565b90600052602060002001549050808760000184815481106140d2576140d2614e9e565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061410557614105615a7f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611467565b6000915050611467565b5092915050565b600082600001828154811061416857614168614e9e565b9060005260206000200154905092915050565b60008181526001830160205260408120546141c257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611467565b506000611467565b50805460008255906000526020600020908101906139e2919061423e565b82805482825590600052602060002090810192821561422e579160200282015b8281111561422e578251829061421e908261556f565b5091602001919060010190614208565b5061423a929150614253565b5090565b5b8082111561423a576000815560010161423f565b8082111561423a5760006142678282614270565b50600101614253565b50805461427c90615290565b6000825580601f1061428c575050565b601f0160209004906000526020600020908101906139e2919061423e565b60ff811681146139e257600080fd5b63ffffffff811681146139e257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff8111828210171561431e5761431e6142cb565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561436b5761436b6142cb565b604052919050565b600067ffffffffffffffff82111561438d5761438d6142cb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126143ca57600080fd5b81356143dd6143d882614373565b614324565b8181528460208386010111156143f257600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561444457600080fd5b873561444f816142aa565b9650602088013561445f816142b9565b9550604088013561446f816142aa565b9450606088013567ffffffffffffffff81111561448b57600080fd5b6144978a828b016143b9565b94505060808801356144a88161440f565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff811681146144d757600080fd5b919050565b6000806000606084860312156144f157600080fd5b83359250614501602085016144c5565b9150604084013590509250925092565b6000806040838503121561452457600080fd5b82359150602083013567ffffffffffffffff81111561454257600080fd5b61454e858286016143b9565b9150509250929050565b60006020828403121561456a57600080fd5b5035919050565b60005b8381101561458c578181015183820152602001614574565b50506000910152565b600081518084526145ad816020860160208601614571565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c116020830184614595565b73ffffffffffffffffffffffffffffffffffffffff811681146139e257600080fd5b600080600080600080600060e0888a03121561462f57600080fd5b873596506020880135614641816145f2565b95506040880135614651816142aa565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806040838503121561468c57600080fd5b8235915061469c602084016144c5565b90509250929050565b6000602082840312156146b757600080fd5b8135611c11816145f2565b60008083601f8401126146d457600080fd5b50813567ffffffffffffffff8111156146ec57600080fd5b6020830191508360208260051b85010111156116bb57600080fd5b600080600080600080600060c0888a03121561472257600080fd5b873567ffffffffffffffff81111561473957600080fd5b6147458a828b016146c2565b9098509650506020880135614759816142aa565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561479657600080fd5b505081359360208301359350604090920135919050565b602081526147d460208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516147ed604084018263ffffffff169052565b50604083015161014080606085015261480a610160850183614595565b9150606085015161482b60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614897818701836bffffffffffffffffffffffff169052565b86015190506101206148ac8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018387015290506148e48382614595565b9695505050505050565b6000806020838503121561490157600080fd5b823567ffffffffffffffff81111561491857600080fd5b614924858286016146c2565b90969095509350505050565b60008083601f84011261494257600080fd5b50813567ffffffffffffffff81111561495a57600080fd5b6020830191508360208285010111156116bb57600080fd5b6000806020838503121561498557600080fd5b823567ffffffffffffffff81111561499c57600080fd5b61492485828601614930565b6020808252825182820181905260009190848201906040850190845b818110156149e0578351835292840192918401916001016149c4565b50909695505050505050565b600067ffffffffffffffff821115614a0657614a066142cb565b5060051b60200190565b60008060408385031215614a2357600080fd5b823567ffffffffffffffff80821115614a3b57600080fd5b818501915085601f830112614a4f57600080fd5b81356020614a5f6143d8836149ec565b82815260059290921b84018101918181019089841115614a7e57600080fd5b8286015b84811015614ab657803586811115614a9a5760008081fd5b614aa88c86838b01016143b9565b845250918301918301614a82565b5096505086013592505080821115614acd57600080fd5b5061454e858286016143b9565b8215158152604060208201526000611c0e6040830184614595565b600080600060408486031215614b0a57600080fd5b833567ffffffffffffffff811115614b2157600080fd5b614b2d868287016146c2565b9094509250506020840135614b41816142b9565b809150509250925092565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b600080600060408486031215614b8357600080fd5b83359250602084013567ffffffffffffffff811115614ba157600080fd5b614bad86828701614930565b9497909650939450505050565b60008060408385031215614bcd57600080fd5b823567ffffffffffffffff80821115614be557600080fd5b614bf1868387016143b9565b93506020850135915080821115614acd57600080fd5b60006020808385031215614c1a57600080fd5b823567ffffffffffffffff80821115614c3257600080fd5b818501915085601f830112614c4657600080fd5b8135614c546143d8826149ec565b81815260059190911b83018401908481019088831115614c7357600080fd5b8585015b83811015614cab57803585811115614c8f5760008081fd5b614c9d8b89838a01016143b9565b845250918601918601614c77565b5098975050505050505050565b60008060408385031215614ccb57600080fd5b823591506020830135614cdd8161440f565b809150509250929050565b600060208284031215614cfa57600080fd5b8135611c11816142aa565b60008060408385031215614d1857600080fd5b823591506020830135614cdd816142b9565b60008060408385031215614d3d57600080fd5b823591506020830135614cdd816142aa565b60008060008060608587031215614d6557600080fd5b843567ffffffffffffffff811115614d7c57600080fd5b614d88878288016146c2565b9095509350506020850135614d9c816142aa565b91506040850135614dac816142aa565b939692955090935050565b60008060008060008060c08789031215614dd057600080fd5b8635614ddb816145f2565b95506020870135614deb816142aa565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614e6a57614e6a614e10565b02949350505050565b805180151581146144d757600080fd5b600060208284031215614e9557600080fd5b611c1182614e73565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614ee357614ee3614e10565b60010192915050565b828152604060208201526000611c0e6040830184614595565b600082601f830112614f1657600080fd5b8151614f246143d882614373565b818152846020838601011115614f3957600080fd5b614f4a826020830160208701614571565b949350505050565b600060208284031215614f6457600080fd5b815167ffffffffffffffff811115614f7b57600080fd5b614f4a84828501614f05565b80516144d78161440f565b600060208284031215614fa457600080fd5b8151611c118161440f565b80516144d7816145f2565b60008060408385031215614fcd57600080fd5b8251614fd8816145f2565b6020939093015192949293505050565b600060208284031215614ffa57600080fd5b8151611c11816145f2565b60006020828403121561501757600080fd5b8151611c11816142aa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b5060010190565b80516144d7816142b9565b805167ffffffffffffffff811681146144d757600080fd5b60006020828403121561508f57600080fd5b815167ffffffffffffffff808211156150a757600080fd5b9083019061014082860312156150bc57600080fd5b6150c46142fa565b6150cd83614faf565b81526150db6020840161505a565b60208201526040830151828111156150f257600080fd5b6150fe87828601614f05565b60408301525061511060608401614f87565b606082015261512160808401614faf565b608082015261513260a08401615065565b60a082015261514360c0840161505a565b60c082015261515460e08401614f87565b60e0820152610100615167818501614e73565b90820152610120838101518381111561517f57600080fd5b61518b88828701614f05565b918301919091525095945050505050565b8082018082111561146757611467614e10565b600061ffff8083168181036151c6576151c6614e10565b6001019392505050565b6000602082840312156151e257600080fd5b5051919050565b8181038181111561146757611467614e10565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015615271577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261525f868351614595565b95509382019390820190600101615225565b5050858403818701525050506152878185614595565b95945050505050565b600181811c908216806152a457607f821691505b6020821081036152dd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008083546152f181615290565b60018281168015615309576001811461533c5761536b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008416875282151583028701945061536b565b8760005260208060002060005b858110156153625781548a820152908401908201615349565b50505082870194505b50929695505050505050565b6000815461538481615290565b8085526020600183811680156153a157600181146153d957615407565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550615407565b866000528260002060005b858110156153ff5781548a82018601529083019084016153e4565b890184019650505b505050505092915050565b60a08152600061542560a0830188615377565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015615497577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526154858383615377565b9486019492506001918201910161544c565b505086810360408801526154ab818b615377565b94505050505084606084015282810360808401526154c98185614595565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f82111561299957600081815260208120601f850160051c810160208610156155505750805b601f850160051c820191505b818110156113a85782815560010161555c565b815167ffffffffffffffff811115615589576155896142cb565b61559d816155978454615290565b84615529565b602080601f8311600181146155f057600084156155ba5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113a8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561563d5788860151825594840194600190910190840161561e565b508582101561567957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b6000602080838503121561569c57600080fd5b825167ffffffffffffffff8111156156b357600080fd5b8301601f810185136156c457600080fd5b80516156d26143d8826149ec565b81815260059190911b820183019083810190878311156156f157600080fd5b928401925b8284101561570f578351825292840192908401906156f6565b979650505050505050565b600063ffffffff8083168181036151c6576151c6614e10565b805160208083015191908110156152dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b6020815260008251610140806020850152615794610160850183614595565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030160408701526157d08483614595565b9350604087015191506157fb606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e087015261585c8483614595565b935060e0870151915061010081878603018188015261587b8584614595565b94508088015192505061012081878603018188015261589a8584614595565b945080880151925050506158bd828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156158ff576158ff614e10565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261594257615942615904565b500490565b818103600083128015838313168383128216171561414a5761414a614e10565b60008261597657615976615904565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156159ca576159ca614e10565b500590565b80820182811260008312801582168215821617156159ef576159ef614e10565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505357615053614e10565b60007f80000000000000000000000000000000000000000000000000000000000000008203615a5957615a59614e10565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"_registrar\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_useArb\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"LogEmittedAgain\",\"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\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"UpkeepTopUp\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BUCKET_SIZE\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"addLinkAmount\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchCancelUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"batchPreparingUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"type\":\"uint8\"}],\"name\":\"batchPreparingUpkeepsSimple\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"number\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performGasToBurn\",\"type\":\"uint256\"}],\"name\":\"batchRegisterUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"batchSendLogs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint32\",\"name\":\"interval\",\"type\":\"uint32\"}],\"name\":\"batchSetIntervals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchUpdatePipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"}],\"name\":\"batchWithdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bucketedDelays\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"buckets\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"burnPerformGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"checkGasToBurns\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"counters\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delays\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedAgainSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emittedSig\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"firstPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"gasLimits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDsDeployedByThisContract\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getAllActiveUpkeepIDsOnRegistry\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getBucketedDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getBucketedDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelays\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getDelaysLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"getLogTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"logTrigger\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"p\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getPxDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"bucket\",\"type\":\"uint16\"}],\"name\":\"getSumDelayInBucket\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getSumDelayLastNPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepInfo\",\"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\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"\",\"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\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"intervals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"lastTopUpBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minBalanceThresholdMultiplier\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performDataSizes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"performGasToBurns\",\"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\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"previousPerformBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registrar\",\"outputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registry\",\"outputs\":[{\"internalType\":\"contractIKeeperRegistryMaster\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"log\",\"type\":\"uint8\"}],\"name\":\"sendLog\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAutomationRegistrar2_1\",\"name\":\"newRegistrar\",\"type\":\"address\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"_feeds\",\"type\":\"string[]\"}],\"name\":\"setFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setInterval\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_timeParamKey\",\"type\":\"string\"}],\"name\":\"setParamKeys\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformDataSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"topUpFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"selector\",\"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\"}],\"name\":\"updateLogTriggerConfig1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"cfg\",\"type\":\"bytes\"}],\"name\":\"updateLogTriggerConfig2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"pipelineData\",\"type\":\"bytes\"}],\"name\":\"updateUpkeepPipelineData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTopUpCheckInterval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"withdrawLinks\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x7f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf086080527fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d60a0526005601455601580546001600160681b0319166c140000000002c68af0bb140000179055606460e0526101c06040526042610140818152610100918291906200622361016039815260200160405180608001604052806042815260200162006265604291399052620000be906016906002620003c7565b506040805180820190915260098152680cccacac892c890caf60bb1b6020820152601790620000ee908262000543565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b602082015260189062000120908262000543565b503480156200012e57600080fd5b50604051620062a7380380620062a7833981016040819052620001519162000625565b81813380600081620001aa5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001dd57620001dd816200031c565b5050601180546001600160a01b0319166001600160a01b038516908117909155604080516330fe427560e21b815281516000945063c3f909d4926004808401939192918290030181865afa1580156200023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000260919062000668565b50601380546001600160a01b0319166001600160a01b038381169190911790915560115460408051631b6b6d2360e01b81529051939450911691631b6b6d23916004808201926020929091908290030181865afa158015620002c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ec919062000699565b601280546001600160a01b0319166001600160a01b039290921691909117905550151560c05250620006c0915050565b336001600160a01b03821603620003765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620001a1565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821562000412579160200282015b8281111562000412578251829062000401908262000543565b5091602001919060010190620003e8565b506200042092915062000424565b5090565b80821115620004205760006200043b828262000445565b5060010162000424565b5080546200045390620004b4565b6000825580601f1062000464575050565b601f01602090049060005260206000209081019062000484919062000487565b50565b5b8082111562000420576000815560010162000488565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004c957607f821691505b602082108103620004ea57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200053e57600081815260208120601f850160051c81016020861015620005195750805b601f850160051c820191505b818110156200053a5782815560010162000525565b5050505b505050565b81516001600160401b038111156200055f576200055f6200049e565b6200057781620005708454620004b4565b84620004f0565b602080601f831160018114620005af5760008415620005965750858301515b600019600386901b1c1916600185901b1785556200053a565b600085815260208120601f198616915b82811015620005e057888601518255948401946001909101908401620005bf565b5085821015620005ff5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b03811681146200048457600080fd5b600080604083850312156200063957600080fd5b825162000646816200060f565b602084015190925080151581146200065d57600080fd5b809150509250929050565b600080604083850312156200067c57600080fd5b825162000689816200060f565b6020939093015192949293505050565b600060208284031215620006ac57600080fd5b8151620006b9816200060f565b9392505050565b60805160a05160c05160e051615b0d62000716600039600081816105b10152611fcc0152600081816109f70152613cf90152600081816108700152613747015260008181610db4015261371c0152615b0d6000f3fe6080604052600436106104f05760003560e01c806379ba509711610294578063a6b594751161015e578063d6051a72116100d6578063e45530831161008a578063fa333dfb1161006f578063fa333dfb14610fc3578063fba7ffa314611076578063fcdc1f63146110a357600080fd5b8063e455308314610f8d578063f2fde38b14610fa357600080fd5b8063daee1aeb116100bb578063daee1aeb14610f20578063dbef701e14610f40578063e0114adb14610f6057600080fd5b8063d6051a7214610ee0578063da6cba4714610f0057600080fd5b8063b657bc9c1161012d578063c041982211610112578063c041982214610e8b578063c98f10b014610eab578063d4c2490014610ec057600080fd5b8063b657bc9c14610e4b578063becde0e114610e6b57600080fd5b8063a6b5947514610dd6578063a72aa27e14610df6578063af953a4a14610e16578063afb28d1f14610e3657600080fd5b80638fcb3fba1161020c5780639b429354116101c05780639d385eaa116101a55780639d385eaa14610d625780639d6f1cc714610d82578063a654824814610da257600080fd5b80639b42935414610d045780639b51fb0d14610d3157600080fd5b8063948108f7116101f1578063948108f714610c9a57806396cebc7c14610cba5780639ac542eb14610cda57600080fd5b80638fcb3fba14610c4d578063924ca57814610c7a57600080fd5b80638243444a1161026357806386e330af1161024857806386e330af14610be2578063873c758614610c025780638da5cb5b14610c2257600080fd5b80638243444a14610ba25780638340507c14610bc257600080fd5b806379ba509714610b2057806379ea994314610b355780637b10399914610b555780637e7a46dc14610b8257600080fd5b80634585e33b116103d55780635f17e6161161034d5780636e04ff0d1161030157806373644cce116102e657806373644cce14610aa65780637672130314610ad3578063776898c814610b0057600080fd5b80636e04ff0d14610a565780637145f11b14610a7657600080fd5b8063636092e811610332578063636092e8146109c0578063642f6cef146109e557806369cdbadb14610a2957600080fd5b80635f17e6161461097357806360457ff51461099357600080fd5b80634b56a42e116103a457806351c98be31161038957806351c98be31461091157806357970e93146109315780635d4ee7f31461095e57600080fd5b80634b56a42e146108bf5780635147cd59146108df57600080fd5b80634585e33b1461081157806345d2ec1714610831578063469820931461085e57806346e7a63e1461089257600080fd5b8063207b65161161046857806329e0a841116104375780632b20e3971161041c5780632b20e39714610772578063328ffd11146107c45780633ebe8d6c146107f157600080fd5b806329e0a841146107255780632a9032d31461075257600080fd5b8063207b6516146106a557806320e3dbd4146106c55780632636aecf146106e557806328c4b57b1461070557600080fd5b806312c55027116104bf5780631cdde251116104a45780631cdde251146106135780631e01043914610633578063206c32e81461067057600080fd5b806312c550271461059f57806319d97a94146105e657600080fd5b806306c1cc00146104fc578063077ac6211461051e5780630b7d33e6146105515780630fb172fb1461057157600080fd5b366104f757005b600080fd5b34801561050857600080fd5b5061051c61051736600461447b565b6110d0565b005b34801561052a57600080fd5b5061053e61053936600461452e565b61131f565b6040519081526020015b60405180910390f35b34801561055d57600080fd5b5061051c61056c366004614563565b61135d565b34801561057d57600080fd5b5061059161058c366004614563565b6113eb565b604051610548929190614618565b3480156105ab57600080fd5b506105d37f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff9091168152602001610548565b3480156105f257600080fd5b50610606610601366004614633565b611403565b604051610548919061464c565b34801561061f57600080fd5b5061051c61062e366004614681565b6114c0565b34801561063f57600080fd5b5061065361064e366004614633565b6115fd565b6040516bffffffffffffffffffffffff9091168152602001610548565b34801561067c57600080fd5b5061069061068b3660046146e6565b611692565b60408051928352602083019190915201610548565b3480156106b157600080fd5b506106066106c0366004614633565b611714565b3480156106d157600080fd5b5061051c6106e0366004614712565b61176c565b3480156106f157600080fd5b5061051c610700366004614774565b611936565b34801561071157600080fd5b5061053e6107203660046147ee565b611bff565b34801561073157600080fd5b50610745610740366004614633565b611c6a565b604051610548919061481a565b34801561075e57600080fd5b5061051c61076d36600461495b565b611d6f565b34801561077e57600080fd5b5060115461079f9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610548565b3480156107d057600080fd5b5061053e6107df366004614633565b60036020526000908152604090205481565b3480156107fd57600080fd5b5061053e61080c366004614633565b611e50565b34801561081d57600080fd5b5061051c61082c3660046149df565b611eb9565b34801561083d57600080fd5b5061085161084c3660046146e6565b6120d8565b6040516105489190614a15565b34801561086a57600080fd5b5061053e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561089e57600080fd5b5061053e6108ad366004614633565b600a6020526000908152604090205481565b3480156108cb57600080fd5b506105916108da366004614a7d565b612147565b3480156108eb57600080fd5b506108ff6108fa366004614633565b61219b565b60405160ff9091168152602001610548565b34801561091d57600080fd5b5061051c61092c366004614b47565b61222f565b34801561093d57600080fd5b5060125461079f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561096a57600080fd5b5061051c6122d3565b34801561097f57600080fd5b5061051c61098e366004614b9e565b61240e565b34801561099f57600080fd5b5061053e6109ae366004614633565b60076020526000908152604090205481565b3480156109cc57600080fd5b50601554610653906bffffffffffffffffffffffff1681565b3480156109f157600080fd5b50610a197f000000000000000000000000000000000000000000000000000000000000000081565b6040519015158152602001610548565b348015610a3557600080fd5b5061053e610a44366004614633565b60086020526000908152604090205481565b348015610a6257600080fd5b50610591610a713660046149df565b6124db565b348015610a8257600080fd5b50610a19610a91366004614633565b600b6020526000908152604090205460ff1681565b348015610ab257600080fd5b5061053e610ac1366004614633565b6000908152600c602052604090205490565b348015610adf57600080fd5b5061053e610aee366004614633565b60046020526000908152604090205481565b348015610b0c57600080fd5b50610a19610b1b366004614633565b612704565b348015610b2c57600080fd5b5061051c612756565b348015610b4157600080fd5b5061079f610b50366004614633565b612853565b348015610b6157600080fd5b5060135461079f9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b8e57600080fd5b5061051c610b9d366004614bc0565b6128e7565b348015610bae57600080fd5b5061051c610bbd366004614bc0565b612978565b348015610bce57600080fd5b5061051c610bdd366004614c0c565b6129d2565b348015610bee57600080fd5b5061051c610bfd366004614c59565b6129f0565b348015610c0e57600080fd5b50610851610c1d366004614b9e565b612a03565b348015610c2e57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661079f565b348015610c5957600080fd5b5061053e610c68366004614633565b60056020526000908152604090205481565b348015610c8657600080fd5b5061051c610c95366004614b9e565b612ac0565b348015610ca657600080fd5b5061051c610cb5366004614d0a565b612d05565b348015610cc657600080fd5b5061051c610cd5366004614d3a565b612e1d565b348015610ce657600080fd5b506015546108ff906c01000000000000000000000000900460ff1681565b348015610d1057600080fd5b5061051c610d1f366004614b9e565b60009182526009602052604090912055565b348015610d3d57600080fd5b506105d3610d4c366004614633565b600e6020526000908152604090205461ffff1681565b348015610d6e57600080fd5b50610851610d7d366004614633565b613027565b348015610d8e57600080fd5b50610606610d9d366004614633565b613089565b348015610dae57600080fd5b5061053e7f000000000000000000000000000000000000000000000000000000000000000081565b348015610de257600080fd5b5061051c610df13660046147ee565b613135565b348015610e0257600080fd5b5061051c610e11366004614d57565b61319e565b348015610e2257600080fd5b5061051c610e31366004614633565b613249565b348015610e4257600080fd5b506106066132cf565b348015610e5757600080fd5b50610653610e66366004614633565b6132dc565b348015610e7757600080fd5b5061051c610e8636600461495b565b613334565b348015610e9757600080fd5b50610851610ea6366004614b9e565b6133ce565b348015610eb757600080fd5b506106066134cb565b348015610ecc57600080fd5b5061051c610edb366004614d7c565b6134d8565b348015610eec57600080fd5b50610690610efb366004614b9e565b613557565b348015610f0c57600080fd5b5061051c610f1b366004614da1565b6135c0565b348015610f2c57600080fd5b5061051c610f3b36600461495b565b613927565b348015610f4c57600080fd5b5061053e610f5b366004614b9e565b6139f2565b348015610f6c57600080fd5b5061053e610f7b366004614633565b60096020526000908152604090205481565b348015610f9957600080fd5b5061053e60145481565b348015610faf57600080fd5b5061051c610fbe366004614712565b613a23565b348015610fcf57600080fd5b50610606610fde366004614e09565b6040805160c0808201835273ffffffffffffffffffffffffffffffffffffffff9890981680825260ff97881660208084019182528385019889526060808501988952608080860198895260a095860197885286519283019490945291519099168985015296519688019690965293519486019490945290519184019190915251828401528051808303909301835260e0909101905290565b34801561108257600080fd5b5061053e611091366004614633565b60066020526000908152604090205481565b3480156110af57600080fd5b5061053e6110be366004614633565b60026020526000908152604090205481565b6040805161018081018252600461014082019081527f746573740000000000000000000000000000000000000000000000000000000061016083015281528151602081810184526000808352818401929092523083850181905263ffffffff8b166060850152608084015260ff808a1660a08501528451808301865283815260c085015260e0840189905284519182019094529081526101008201526bffffffffffffffffffffffff8516610120820152601254601154919273ffffffffffffffffffffffffffffffffffffffff9182169263095ea7b39216906111b6908c1688614e91565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526bffffffffffffffffffffffff1660248201526044016020604051808303816000875af1158015611234573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112589190614ed5565b5060008860ff1667ffffffffffffffff8111156112775761127761431d565b6040519080825280602002602001820160405280156112a0578160200160208202803683370190505b50905060005b8960ff168160ff1610156113135760006112bf84613a37565b905080838360ff16815181106112d7576112d7614ef0565b6020908102919091018101919091526000918252600881526040808320889055600790915290208490558061130b81614f1f565b9150506112a6565b50505050505050505050565b600d602052826000526040600020602052816000526040600020818154811061134757600080fd5b9060005260206000200160009250925050505481565b6013546040517f0b7d33e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690630b7d33e6906113b59085908590600401614f3e565b600060405180830381600087803b1580156113cf57600080fd5b505af11580156113e3573d6000803e3d6000fd5b505050505050565b604080516000808252602082019092525b9250929050565b6013546040517f19d97a940000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff16906319d97a94906024015b600060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114ba9190810190614fa4565b92915050565b6013546040517ffa333dfb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260ff8816602483015260448201879052606482018690526084820185905260a4820184905290911690634ee88d35908990309063fa333dfb9060c401600060405180830381865afa15801561155f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115a59190810190614fa4565b6040518363ffffffff1660e01b81526004016115c2929190614f3e565b600060405180830381600087803b1580156115dc57600080fd5b505af11580156115f0573d6000803e3d6000fd5b5050505050505050505050565b6013546040517f1e0104390000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690631e010439906024015b602060405180830381865afa15801561166e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ba9190614fe4565b6000828152600d6020908152604080832061ffff8516845282528083208054825181850281018501909352808352849384939291908301828280156116f657602002820191906000526020600020905b8154815260200190600101908083116116e2575b50505050509050611708818251613b05565b92509250509250929050565b6013546040517f207b65160000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063207b651690602401611457565b601180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080517fc3f909d400000000000000000000000000000000000000000000000000000000815281516000939263c3f909d492600480820193918290030181865afa158015611802573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611826919061500c565b50601380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691909117909155601154604080517f1b6b6d230000000000000000000000000000000000000000000000000000000081529051939450911691631b6b6d23916004808201926020929091908290030181865afa1580156118c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ed919061503a565b601280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b8560005b81811015611bf457600089898381811061195657611956614ef0565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161198f91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016119bb929190614f3e565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190615057565b90508060ff16600103611bdf576040517ffa333dfb000000000000000000000000000000000000000000000000000000008152306004820181905260ff8b166024830152604482018a9052606482018890526084820188905260a4820187905260009163fa333dfb9060c401600060405180830381865afa158015611b0c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611b529190810190614fa4565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d3590611bab9086908590600401614f3e565b600060405180830381600087803b158015611bc557600080fd5b505af1158015611bd9573d6000803e3d6000fd5b50505050505b50508080611bec90615074565b91505061193a565b505050505050505050565b6000838152600c602090815260408083208054825181850281018501909352808352611c6093830182828015611c5457602002820191906000526020600020905b815481526020019060010190808311611c40575b50505050508484613b8a565b90505b9392505050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c7c3a19a90602401600060405180830381865afa158015611d29573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114ba91908101906150cf565b8060005b818160ff161015611e4a5760135473ffffffffffffffffffffffffffffffffffffffff1663c8048022858560ff8516818110611db157611db1614ef0565b905060200201356040518263ffffffff1660e01b8152600401611dd691815260200190565b600060405180830381600087803b158015611df057600080fd5b505af1158015611e04573d6000803e3d6000fd5b50505050611e3784848360ff16818110611e2057611e20614ef0565b90506020020135600f613ce990919063ffffffff16565b5080611e4281614f1f565b915050611d73565b50505050565b6000818152600e602052604081205461ffff1681805b8261ffff168161ffff1611611eb1576000858152600d6020908152604080832061ffff85168452909152902054611e9d90836151ee565b915080611ea981615201565b915050611e66565b509392505050565b60005a9050600080611ecd84860186614a7d565b91509150600081806020019051810190611ee79190615222565b60008181526005602090815260408083205460049092528220549293509190611f0e613cf5565b905082600003611f2e576000848152600560205260409020819055612089565b600084815260036020526040812054611f47848461523b565b611f51919061523b565b6000868152600e6020908152604080832054600d835281842061ffff909116808552908352818420805483518186028101860190945280845295965090949192909190830182828015611fc357602002820191906000526020600020905b815481526020019060010190808311611faf575b505050505090507f000000000000000000000000000000000000000000000000000000000000000061ffff1681510361203e578161200081615201565b6000898152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83161790559250505b506000868152600d6020908152604080832061ffff909416835292815282822080546001818101835591845282842001859055888352600c8252928220805493840181558252902001555b6000848152600660205260408120546120a39060016151ee565b60008681526006602090815260408083208490556004909152902083905590506120cd8583612ac0565b611313858984613135565b6000828152600d6020908152604080832061ffff8516845282529182902080548351818402810184019094528084526060939283018282801561213a57602002820191906000526020600020905b815481526020019060010190808311612126575b5050505050905092915050565b600060606000848460405160200161216092919061524e565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b6013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690635147cd5990602401602060405180830381865afa15801561220b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ba9190615057565b8160005b818110156122cc5730635f17e61686868481811061225357612253614ef0565b90506020020135856040518363ffffffff1660e01b815260040161228792919091825263ffffffff16602082015260400190565b600060405180830381600087803b1580156122a157600080fd5b505af11580156122b5573d6000803e3d6000fd5b5050505080806122c490615074565b915050612233565b5050505050565b6122db613d97565b6012546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e9190615222565b6012546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526024810183905291925073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156123e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240a9190614ed5565b5050565b60008281526003602090815260408083208490556005825280832083905560068252808320839055600c90915281206124469161421c565b6000828152600e602052604081205461ffff16905b8161ffff168161ffff16116124a2576000848152600d6020908152604080832061ffff8516845290915281206124909161421c565b8061249a81615201565b91505061245b565b5050506000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055565b6000606060005a905060006124f285870187614633565b60008181526009602090815260408083205460089092528220549293509190838367ffffffffffffffff81111561252b5761252b61431d565b6040519080825280601f01601f191660200182016040528015612555576020820181803683370190505b50604051602001612567929190614f3e565b60405160208183030381529060405290506000612582613cf5565b9050600061258f86612704565b90505b835a61259e908961523b565b6125aa906127106151ee565b10156125eb5781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055612592565b806126035760008398509850505050505050506113fc565b6040517f6665656449644865780000000000000000000000000000000000000000000000602082015260009060290160405160208183030381529060405280519060200120601760405160200161265a9190615335565b604051602081830303815290604052805190602001200361267c57508161267f565b50425b601760166018838a60405160200161269991815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526126fb9594939291600401615464565b60405180910390fd5b600081815260056020526040812054810361272157506001919050565b600082815260036020908152604080832054600490925290912054612744613cf5565b61274e919061523b565b101592915050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146127d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016126fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6013546040517f79ea99430000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff16906379ea994390602401602060405180830381865afa1580156128c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ba919061503a565b6013546040517fcd7f71b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063cd7f71b59061294190869086908690600401615527565b600060405180830381600087803b15801561295b57600080fd5b505af115801561296f573d6000803e3d6000fd5b50505050505050565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690634ee88d359061294190869086908690600401615527565b60176129de83826155c1565b5060186129eb82826155c1565b505050565b805161240a90601690602084019061423a565b6013546040517f06e3b632000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260609173ffffffffffffffffffffffffffffffffffffffff16906306e3b63290604401600060405180830381865afa158015612a7a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611c6391908101906156db565b601454600083815260026020526040902054612adc908361523b565b111561240a576013546040517fc7c3a19a0000000000000000000000000000000000000000000000000000000081526004810184905260009173ffffffffffffffffffffffffffffffffffffffff169063c7c3a19a90602401600060405180830381865afa158015612b52573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b9891908101906150cf565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810186905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063b657bc9c90602401602060405180830381865afa158015612c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c319190614fe4565b601554909150612c559082906c01000000000000000000000000900460ff16614e91565b6bffffffffffffffffffffffff1682606001516bffffffffffffffffffffffff161015611e4a57601554612c989085906bffffffffffffffffffffffff16612d05565b60008481526002602090815260409182902085905560155482518781526bffffffffffffffffffffffff909116918101919091529081018490527f49d4100ab0124eb4a9a65dc4ea08d6412a43f6f05c49194983f5b322bcc0a5c09060600160405180910390a150505050565b6012546013546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526bffffffffffffffffffffffff8416602482015291169063095ea7b3906044016020604051808303816000875af1158015612d8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db19190614ed5565b506013546040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063948108f7906044016113b5565b6040517fc04198220000000000000000000000000000000000000000000000000000000081526000600482018190526024820181905290309063c041982290604401600060405180830381865afa158015612e7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612ec291908101906156db565b80519091506000612ed1613cf5565b905060005b828110156122cc576000848281518110612ef257612ef2614ef0565b60209081029190910101516013546040517f5147cd590000000000000000000000000000000000000000000000000000000081526004810183905291925060009173ffffffffffffffffffffffffffffffffffffffff90911690635147cd5990602401602060405180830381865afa158015612f72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f969190615057565b90508060ff16600103613012578660ff16600003612fe2576040513090859084907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4613012565b6040513090859084907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a45b5050808061301f90615074565b915050612ed6565b6000818152600c602090815260409182902080548351818402810184019094528084526060939283018282801561307d57602002820191906000526020600020905b815481526020019060010190808311613069575b50505050509050919050565b6016818154811061309957600080fd5b9060005260206000200160009150905080546130b4906152e2565b80601f01602080910402602001604051908101604052809291908181526020018280546130e0906152e2565b801561312d5780601f106131025761010080835404028352916020019161312d565b820191906000526020600020905b81548152906001019060200180831161311057829003601f168201915b505050505081565b6000838152600760205260409020545b805a613151908561523b565b61315d906127106151ee565b1015611e4a5781406000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055613145565b6013546040517fa72aa27e0000000000000000000000000000000000000000000000000000000081526004810184905263ffffffff8316602482015273ffffffffffffffffffffffffffffffffffffffff9091169063a72aa27e90604401600060405180830381600087803b15801561321657600080fd5b505af115801561322a573d6000803e3d6000fd5b505050600092835250600a602052604090912063ffffffff9091169055565b6013546040517f744bfe610000000000000000000000000000000000000000000000000000000081526004810183905230602482015273ffffffffffffffffffffffffffffffffffffffff9091169063744bfe6190604401600060405180830381600087803b1580156132bb57600080fd5b505af11580156122cc573d6000803e3d6000fd5b601780546130b4906152e2565b6013546040517fb657bc9c0000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff169063b657bc9c90602401611651565b8060005b818163ffffffff161015611e4a573063af953a4a858563ffffffff851681811061336457613364614ef0565b905060200201356040518263ffffffff1660e01b815260040161338991815260200190565b600060405180830381600087803b1580156133a357600080fd5b505af11580156133b7573d6000803e3d6000fd5b5050505080806133c69061576c565b915050613338565b606060006133dc600f613e1a565b9050808410613417576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361342c57613429848261523b565b92505b60008367ffffffffffffffff8111156134475761344761431d565b604051908082528060200260200182016040528015613470578160200160208202803683370190505b50905060005b848110156134c25761349361348b82886151ee565b600f90613e24565b8282815181106134a5576134a5614ef0565b6020908102919091010152806134ba81615074565b915050613476565b50949350505050565b601880546130b4906152e2565b60006134e2613cf5565b90508160ff16600003613523576040513090829085907f97009585a4d2440f981ab6f6eec514343e1e6b2aa9b991a26998e6806f41bf0890600090a4505050565b6040513090829085907fc76416badc8398ce17c93eab7b4f60f263241694cf503e4df24f233a8cc1c50d90600090a4505050565b6000828152600c602090815260408083208054825181850281018501909352808352849384939291908301828280156135af57602002820191906000526020600020905b81548152602001906001019080831161359b575b505050505090506117088185613b05565b8260005b818110156113e35760008686838181106135e0576135e0614ef0565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161361991815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401613645929190614f3e565b600060405180830381600087803b15801561365f57600080fd5b505af1158015613673573d6000803e3d6000fd5b50506013546040517f5147cd59000000000000000000000000000000000000000000000000000000008152600481018590526000935073ffffffffffffffffffffffffffffffffffffffff9091169150635147cd5990602401602060405180830381865afa1580156136e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061370d9190615057565b90508060ff16600103613912577f000000000000000000000000000000000000000000000000000000000000000060ff87161561376757507f00000000000000000000000000000000000000000000000000000000000000005b60003073ffffffffffffffffffffffffffffffffffffffff1663fa333dfb3089858860405160200161379b91815260200190565b6040516020818303038152906040526137b390615785565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff909416600485015260ff90921660248401526044830152606482015260006084820181905260a482015260c401600060405180830381865afa15801561383e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526138849190810190614fa4565b6013546040517f4ee88d3500000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690634ee88d35906138dd9087908590600401614f3e565b600060405180830381600087803b1580156138f757600080fd5b505af115801561390b573d6000803e3d6000fd5b5050505050505b5050808061391f90615074565b9150506135c4565b8060005b81811015611e4a57600084848381811061394757613947614ef0565b9050602002013590503073ffffffffffffffffffffffffffffffffffffffff16637e7a46dc828360405160200161398091815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016139ac929190614f3e565b600060405180830381600087803b1580156139c657600080fd5b505af11580156139da573d6000803e3d6000fd5b505050505080806139ea90615074565b91505061392b565b600c6020528160005260406000208181548110613a0e57600080fd5b90600052602060002001600091509150505481565b613a2b613d97565b613a3481613e30565b50565b6011546040517f3f678e11000000000000000000000000000000000000000000000000000000008152600091829173ffffffffffffffffffffffffffffffffffffffff90911690633f678e1190613a929086906004016157c7565b6020604051808303816000875af1158015613ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad59190615222565b9050613ae2600f82613f25565b506060909201516000838152600a6020526040902063ffffffff90911690555090565b815160009081908190841580613b1b5750808510155b15613b24578094505b60008092505b85831015613b8057866001613b3f858561523b565b613b49919061523b565b81518110613b5957613b59614ef0565b602002602001015181613b6c91906151ee565b905082613b7881615074565b935050613b2a565b9694955050505050565b82516000908190831580613b9e5750808410155b15613ba7578093505b60008467ffffffffffffffff811115613bc257613bc261431d565b604051908082528060200260200182016040528015613beb578160200160208202803683370190505b509050600092505b84831015613c5957866001613c08858561523b565b613c12919061523b565b81518110613c2257613c22614ef0565b6020026020010151818481518110613c3c57613c3c614ef0565b602090810291909101015282613c5181615074565b935050613bf3565b613c7281600060018451613c6d919061523b565b613f31565b85606403613cab578060018251613c89919061523b565b81518110613c9957613c99614ef0565b60200260200101519350505050611c63565b806064825188613cbb9190615919565b613cc59190615985565b81518110613cd557613cd5614ef0565b602002602001015193505050509392505050565b6000611c6383836140a9565b60007f000000000000000000000000000000000000000000000000000000000000000015613d9257606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d8d9190615222565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff163314613e18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016126fb565b565b60006114ba825490565b6000611c6383836141a3565b3373ffffffffffffffffffffffffffffffffffffffff821603613eaf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016126fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611c6383836141cd565b8181808203613f41575050505050565b6000856002613f508787615999565b613f5a91906159b9565b613f649087615a21565b81518110613f7457613f74614ef0565b602002602001015190505b818313614083575b80868481518110613f9a57613f9a614ef0565b60200260200101511015613fba5782613fb281615a49565b935050613f87565b858281518110613fcc57613fcc614ef0565b6020026020010151811015613fed5781613fe581615a7a565b925050613fba565b81831361407e5785828151811061400657614006614ef0565b602002602001015186848151811061402057614020614ef0565b602002602001015187858151811061403a5761403a614ef0565b6020026020010188858151811061405357614053614ef0565b6020908102919091010191909152528261406c81615a49565b935050818061407a90615a7a565b9250505b613f7f565b8185121561409657614096868684613f31565b838312156113e3576113e3868486613f31565b600081815260018301602052604081205480156141925760006140cd60018361523b565b85549091506000906140e19060019061523b565b905081811461414657600086600001828154811061410157614101614ef0565b906000526020600020015490508087600001848154811061412457614124614ef0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061415757614157615ad1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506114ba565b60009150506114ba565b5092915050565b60008260000182815481106141ba576141ba614ef0565b9060005260206000200154905092915050565b6000818152600183016020526040812054614214575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556114ba565b5060006114ba565b5080546000825590600052602060002090810190613a349190614290565b828054828255906000526020600020908101928215614280579160200282015b82811115614280578251829061427090826155c1565b509160200191906001019061425a565b5061428c9291506142a5565b5090565b5b8082111561428c5760008155600101614291565b8082111561428c5760006142b982826142c2565b506001016142a5565b5080546142ce906152e2565b6000825580601f106142de575050565b601f016020900490600052602060002090810190613a349190614290565b60ff81168114613a3457600080fd5b63ffffffff81168114613a3457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156143705761437061431d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156143bd576143bd61431d565b604052919050565b600067ffffffffffffffff8211156143df576143df61431d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261441c57600080fd5b813561442f61442a826143c5565b614376565b81815284602083860101111561444457600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff81168114613a3457600080fd5b600080600080600080600060e0888a03121561449657600080fd5b87356144a1816142fc565b965060208801356144b18161430b565b955060408801356144c1816142fc565b9450606088013567ffffffffffffffff8111156144dd57600080fd5b6144e98a828b0161440b565b94505060808801356144fa81614461565b9699959850939692959460a0840135945060c09093013592915050565b803561ffff8116811461452957600080fd5b919050565b60008060006060848603121561454357600080fd5b8335925061455360208501614517565b9150604084013590509250925092565b6000806040838503121561457657600080fd5b82359150602083013567ffffffffffffffff81111561459457600080fd5b6145a08582860161440b565b9150509250929050565b60005b838110156145c55781810151838201526020016145ad565b50506000910152565b600081518084526145e68160208601602086016145aa565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000611c6060408301846145ce565b60006020828403121561464557600080fd5b5035919050565b602081526000611c6360208301846145ce565b73ffffffffffffffffffffffffffffffffffffffff81168114613a3457600080fd5b600080600080600080600060e0888a03121561469c57600080fd5b8735965060208801356146ae8161465f565b955060408801356146be816142fc565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080604083850312156146f957600080fd5b8235915061470960208401614517565b90509250929050565b60006020828403121561472457600080fd5b8135611c638161465f565b60008083601f84011261474157600080fd5b50813567ffffffffffffffff81111561475957600080fd5b6020830191508360208260051b85010111156113fc57600080fd5b600080600080600080600060c0888a03121561478f57600080fd5b873567ffffffffffffffff8111156147a657600080fd5b6147b28a828b0161472f565b90985096505060208801356147c6816142fc565b96999598509596604081013596506060810135956080820135955060a0909101359350915050565b60008060006060848603121561480357600080fd5b505081359360208301359350604090920135919050565b6020815261484160208201835173ffffffffffffffffffffffffffffffffffffffff169052565b6000602083015161485a604084018263ffffffff169052565b5060408301516101408060608501526148776101608501836145ce565b9150606085015161489860808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614904818701836bffffffffffffffffffffffff169052565b86015190506101206149198682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00183870152905061495183826145ce565b9695505050505050565b6000806020838503121561496e57600080fd5b823567ffffffffffffffff81111561498557600080fd5b6149918582860161472f565b90969095509350505050565b60008083601f8401126149af57600080fd5b50813567ffffffffffffffff8111156149c757600080fd5b6020830191508360208285010111156113fc57600080fd5b600080602083850312156149f257600080fd5b823567ffffffffffffffff811115614a0957600080fd5b6149918582860161499d565b6020808252825182820181905260009190848201906040850190845b81811015614a4d57835183529284019291840191600101614a31565b50909695505050505050565b600067ffffffffffffffff821115614a7357614a7361431d565b5060051b60200190565b60008060408385031215614a9057600080fd5b823567ffffffffffffffff80821115614aa857600080fd5b818501915085601f830112614abc57600080fd5b81356020614acc61442a83614a59565b82815260059290921b84018101918181019089841115614aeb57600080fd5b8286015b84811015614b2357803586811115614b075760008081fd5b614b158c86838b010161440b565b845250918301918301614aef565b5096505086013592505080821115614b3a57600080fd5b506145a08582860161440b565b600080600060408486031215614b5c57600080fd5b833567ffffffffffffffff811115614b7357600080fd5b614b7f8682870161472f565b9094509250506020840135614b938161430b565b809150509250925092565b60008060408385031215614bb157600080fd5b50508035926020909101359150565b600080600060408486031215614bd557600080fd5b83359250602084013567ffffffffffffffff811115614bf357600080fd5b614bff8682870161499d565b9497909650939450505050565b60008060408385031215614c1f57600080fd5b823567ffffffffffffffff80821115614c3757600080fd5b614c438683870161440b565b93506020850135915080821115614b3a57600080fd5b60006020808385031215614c6c57600080fd5b823567ffffffffffffffff80821115614c8457600080fd5b818501915085601f830112614c9857600080fd5b8135614ca661442a82614a59565b81815260059190911b83018401908481019088831115614cc557600080fd5b8585015b83811015614cfd57803585811115614ce15760008081fd5b614cef8b89838a010161440b565b845250918601918601614cc9565b5098975050505050505050565b60008060408385031215614d1d57600080fd5b823591506020830135614d2f81614461565b809150509250929050565b600060208284031215614d4c57600080fd5b8135611c63816142fc565b60008060408385031215614d6a57600080fd5b823591506020830135614d2f8161430b565b60008060408385031215614d8f57600080fd5b823591506020830135614d2f816142fc565b60008060008060608587031215614db757600080fd5b843567ffffffffffffffff811115614dce57600080fd5b614dda8782880161472f565b9095509350506020850135614dee816142fc565b91506040850135614dfe816142fc565b939692955090935050565b60008060008060008060c08789031215614e2257600080fd5b8635614e2d8161465f565b95506020870135614e3d816142fc565b95989597505050506040840135936060810135936080820135935060a0909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80831681851681830481118215151615614ebc57614ebc614e62565b02949350505050565b8051801515811461452957600080fd5b600060208284031215614ee757600080fd5b611c6382614ec5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff8103614f3557614f35614e62565b60010192915050565b828152604060208201526000611c6060408301846145ce565b600082601f830112614f6857600080fd5b8151614f7661442a826143c5565b818152846020838601011115614f8b57600080fd5b614f9c8260208301602087016145aa565b949350505050565b600060208284031215614fb657600080fd5b815167ffffffffffffffff811115614fcd57600080fd5b614f9c84828501614f57565b805161452981614461565b600060208284031215614ff657600080fd5b8151611c6381614461565b80516145298161465f565b6000806040838503121561501f57600080fd5b825161502a8161465f565b6020939093015192949293505050565b60006020828403121561504c57600080fd5b8151611c638161465f565b60006020828403121561506957600080fd5b8151611c63816142fc565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150a5576150a5614e62565b5060010190565b80516145298161430b565b805167ffffffffffffffff8116811461452957600080fd5b6000602082840312156150e157600080fd5b815167ffffffffffffffff808211156150f957600080fd5b90830190610140828603121561510e57600080fd5b61511661434c565b61511f83615001565b815261512d602084016150ac565b602082015260408301518281111561514457600080fd5b61515087828601614f57565b60408301525061516260608401614fd9565b606082015261517360808401615001565b608082015261518460a084016150b7565b60a082015261519560c084016150ac565b60c08201526151a660e08401614fd9565b60e08201526101006151b9818501614ec5565b9082015261012083810151838111156151d157600080fd5b6151dd88828701614f57565b918301919091525095945050505050565b808201808211156114ba576114ba614e62565b600061ffff80831681810361521857615218614e62565b6001019392505050565b60006020828403121561523457600080fd5b5051919050565b818103818111156114ba576114ba614e62565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156152c3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526152b18683516145ce565b95509382019390820190600101615277565b5050858403818701525050506152d981856145ce565b95945050505050565b600181811c908216806152f657607f821691505b60208210810361532f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000808354615343816152e2565b6001828116801561535b576001811461538e576153bd565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506153bd565b8760005260208060002060005b858110156153b45781548a82015290840190820161539b565b50505082870194505b50929695505050505050565b600081546153d6816152e2565b8085526020600183811680156153f3576001811461542b57615459565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550615459565b866000528260002060005b858110156154515781548a8201860152908301908401615436565b890184019650505b505050505092915050565b60a08152600061547760a08301886153c9565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b838110156154e9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526154d783836153c9565b9486019492506001918201910161549e565b505086810360408801526154fd818b6153c9565b945050505050846060840152828103608084015261551b81856145ce565b98975050505050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b601f8211156129eb57600081815260208120601f850160051c810160208610156155a25750805b601f850160051c820191505b818110156113e3578281556001016155ae565b815167ffffffffffffffff8111156155db576155db61431d565b6155ef816155e984546152e2565b8461557b565b602080601f831160018114615642576000841561560c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556113e3565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561568f57888601518255948401946001909101908401615670565b50858210156156cb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083850312156156ee57600080fd5b825167ffffffffffffffff81111561570557600080fd5b8301601f8101851361571657600080fd5b805161572461442a82614a59565b81815260059190911b8201830190838101908783111561574357600080fd5b928401925b8284101561576157835182529284019290840190615748565b979650505050505050565b600063ffffffff80831681810361521857615218614e62565b8051602080830151919081101561532f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b60208152600082516101408060208501526157e66101608501836145ce565b915060208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08086850301604087015261582284836145ce565b93506040870151915061584d606087018373ffffffffffffffffffffffffffffffffffffffff169052565b606087015163ffffffff811660808801529150608087015173ffffffffffffffffffffffffffffffffffffffff811660a0880152915060a087015160ff811660c0880152915060c08701519150808685030160e08701526158ae84836145ce565b935060e087015191506101008187860301818801526158cd85846145ce565b9450808801519250506101208187860301818801526158ec85846145ce565b9450808801519250505061590f828601826bffffffffffffffffffffffff169052565b5090949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561595157615951614e62565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261599457615994615956565b500490565b818103600083128015838313168383128216171561419c5761419c614e62565b6000826159c8576159c8615956565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615a1c57615a1c614e62565b500590565b8082018281126000831280158216821582161715615a4157615a41614e62565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036150a5576150a5614e62565b60007f80000000000000000000000000000000000000000000000000000000000000008203615aab57615aab614e62565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var VerifiableLoadStreamsLookupUpkeepABI = VerifiableLoadStreamsLookupUpkeepMetaData.ABI @@ -295,6 +295,36 @@ func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepCalle return _VerifiableLoadStreamsLookupUpkeep.Contract.CheckCallback(&_VerifiableLoadStreamsLookupUpkeep.CallOpts, values, extraData) } +func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _VerifiableLoadStreamsLookupUpkeep.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _VerifiableLoadStreamsLookupUpkeep.Contract.CheckErrorHandler(&_VerifiableLoadStreamsLookupUpkeep.CallOpts, errCode, extraData) +} + +func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _VerifiableLoadStreamsLookupUpkeep.Contract.CheckErrorHandler(&_VerifiableLoadStreamsLookupUpkeep.CallOpts, errCode, extraData) +} + func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepCaller) CheckGasToBurns(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { var out []interface{} err := _VerifiableLoadStreamsLookupUpkeep.contract.Call(opts, &out, "checkGasToBurns", arg0) @@ -2228,6 +2258,11 @@ func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeepFilte return event, nil } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} + func (_VerifiableLoadStreamsLookupUpkeep *VerifiableLoadStreamsLookupUpkeep) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _VerifiableLoadStreamsLookupUpkeep.abi.Events["LogEmitted"].ID: @@ -2281,6 +2316,10 @@ type VerifiableLoadStreamsLookupUpkeepInterface interface { CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + CheckGasToBurns(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) Counters(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 96eaf97c2d7..054f55e6e27 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 @@ -49,7 +49,7 @@ keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0/Keeper 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 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 4b129ab93432c95ff9143f0631323e189887668889e0b36ccccf18a571e41ccf -log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 +log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin 920fff3b662909f12ed11b47d168036ffa74ad52070a94e2fa26cdad5e428b4e 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 mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.bin 1c52c24f797b8482aa12b8251dcea1c072827bd5b3426b822621261944b99ca0 @@ -71,16 +71,16 @@ solidity_vrf_request_id_v08: ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHel solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.bin f37f8b21a81c113085c6137835a2246db6ebda07da455c4f2b5c7ec60c725c3b solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF/VRF.abi ../../contracts/solc/v0.6/VRF/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 -streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 -streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.bin b1a598963cacac51ed4706538d0f142bdc0d94b9a4b13e2d402131cdf05c9bcf +streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.bin 2861f553fb4731e89126b13319462df674727005a51982d1e617e2c2e44fa422 +streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.bin 37e3a61091cc2a156539dd4aaff987e07577118aa02e97931a647df55705465e test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin 98cb0dc06c15af5dcd3b53bdfc98e7ed2489edc96a42203294ac2fc0efdda02b type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e upkeep_counter_wrapper: ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a -verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.bin fb674ba44c0e8f3b385cd10b2f7dea5cd07b5f38df08066747e8b1542e152557 -verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.bin 785f68c44bfff070505eaa65e38a1af94046e5f9afc1189bcf2c8cfcd1102d66 +verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep/VerifiableLoadLogTriggerUpkeep.bin ee5c608e4e84c80934e42b0c02a49624840adf10b50c91f688bf8f0c7c6994c2 +verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.bin 58f1f6b31a313e04ceb3e0e0f0393bc195cc2f4784a3b0e14a80a86fc836f427 verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.bin a3e02c43756ea91e7ce4b81e48c11648f1d12f6663c236780147e41dfa36ebee vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index 4825499601d..183cafc9d37 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -309,16 +309,17 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { checkResults := []ocr2keepers.CheckResult{automationCheckResult} var values [][]byte - values, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0) + var errCode encoding.ErrCode + values, errCode, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0) if checkResults[0].IneligibilityReason == uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) { resolveIneligible("upkeep used invalid revert data") } - if checkResults[0].PipelineExecutionState == uint8(encoding.InvalidMercuryRequest) { - resolveIneligible("the data streams request data is invalid") - } if err != nil { - failCheckConfig("failed to do data streams request ", err) + failCheckConfig("pipeline execution error, failed to do data streams request ", err) + } + if errCode != encoding.ErrCodeNil { + failCheckConfig(fmt.Sprintf("data streams error, failed to do data streams request with error code %d", errCode), nil) } // do checkCallback 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 1f93fd3ee22..d455e17406a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -1,6 +1,8 @@ package encoding import ( + "net/http" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" @@ -31,18 +33,58 @@ const ( UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 // pipeline execution error - 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 + NoPipelineError PipelineExecutionState = 0 + CheckBlockTooOld PipelineExecutionState = 1 + CheckBlockInvalid PipelineExecutionState = 2 + RpcFlakyFailure PipelineExecutionState = 3 + MercuryFlakyFailure PipelineExecutionState = 4 + PackUnpackDecodeFailed PipelineExecutionState = 5 + PrivilegeConfigUnmarshalError PipelineExecutionState = 6 ) +// ErrCode is used for invoking an error handler with a specific error code. +type ErrCode uint32 + +const ( + ErrCodeNil ErrCode = 0 + ErrCodeStreamsPartialContent ErrCode = 808206 + ErrCodeStreamsBadRequest ErrCode = 808400 + ErrCodeStreamsUnauthorized ErrCode = 808401 + ErrCodeStreamsNotFound ErrCode = 808404 + ErrCodeStreamsInternalError ErrCode = 808500 + ErrCodeStreamsBadGateway ErrCode = 808502 + ErrCodeStreamsServiceUnavailable ErrCode = 808503 + ErrCodeStreamsStatusGatewayTimeout ErrCode = 808504 + ErrCodeStreamsBadResponse ErrCode = 808600 + ErrCodeStreamsTimeout ErrCode = 808601 + ErrCodeStreamsUnknownError ErrCode = 808700 +) + +func HttpToStreamsErrCode(statusCode int) ErrCode { + switch statusCode { + case http.StatusOK: + return ErrCodeNil + case http.StatusPartialContent: + return ErrCodeStreamsPartialContent + case http.StatusBadRequest: + return ErrCodeStreamsBadRequest + case http.StatusUnauthorized: + return ErrCodeStreamsUnauthorized + case http.StatusNotFound: + return ErrCodeStreamsNotFound + case http.StatusInternalServerError: + return ErrCodeStreamsInternalError + case http.StatusBadGateway: + return ErrCodeStreamsBadGateway + case http.StatusServiceUnavailable: + return ErrCodeStreamsServiceUnavailable + case http.StatusGatewayTimeout: + return ErrCodeStreamsStatusGatewayTimeout + default: + return ErrCodeStreamsUnknownError + } +} + type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo type Packer interface { 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 d24442b6ee9..4ec62b243d1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go @@ -10,6 +10,7 @@ import ( "net/http" "time" + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/ethereum/go-ethereum/accounts/abi" @@ -26,7 +27,9 @@ const ( BlockNumber = "blockNumber" // valid for v0.2 Timestamp = "timestamp" // valid for v0.3 totalFastPluginRetries = 5 - totalMediumPluginRetries = 10 + totalMediumPluginRetries = totalFastPluginRetries + 1 + RetryIntervalTimeout = time.Duration(-1) + RequestTimeout = 10 * time.Second ) var GenerateHMACFn = func(method string, path string, body []byte, clientId string, secret string, ts int64) string { @@ -44,9 +47,8 @@ var GenerateHMACFn = func(method string, path string, body []byte, clientId stri return userHmac } -// CalculateRetryConfig returns plugin retry interval based on how many times plugin has retried this work -var CalculateRetryConfigFn = func(prk string, mercuryConfig MercuryConfigProvider) time.Duration { - var retryInterval time.Duration +// CalculateStreamsRetryConfig returns plugin retry interval based on how many times plugin has retried this work +var CalculateStreamsRetryConfigFn = func(upkeepType automationTypes.UpkeepType, prk string, mercuryConfig MercuryConfigProvider) (retryInterval time.Duration) { var retries int totalAttempts, ok := mercuryConfig.GetPluginRetry(prk) if ok { @@ -55,22 +57,27 @@ var CalculateRetryConfigFn = func(prk string, mercuryConfig MercuryConfigProvide retryInterval = 1 * time.Second } else if retries < totalMediumPluginRetries { retryInterval = 5 * time.Second + } else { + retryInterval = RetryIntervalTimeout } - // if the core node has retried totalMediumPluginRetries times, do not set retry interval and plugin will use - // the default interval } else { retryInterval = 1 * time.Second } + if upkeepType == automationTypes.ConditionTrigger { + // Conditional Upkees don't have any pipeline retries as they automatically get checked on a new block + retryInterval = RetryIntervalTimeout + } mercuryConfig.SetPluginRetry(prk, retries+1, cache.DefaultExpiration) return retryInterval } type MercuryData struct { Index int - Error error - Retryable bool - Bytes [][]byte - State encoding.PipelineExecutionState + Bytes [][]byte // Mercury values if request is successful + ErrCode encoding.ErrCode // Error code if mercury gives an error + State encoding.PipelineExecutionState // NoPipelineError if no error during execution, otherwise appropriate error + Retryable bool // Applicable if State != NoPipelineError + Error error // non nil if State != NoPipelineError } type MercuryConfigProvider interface { @@ -86,7 +93,14 @@ type HttpClient interface { } type MercuryClient interface { - DoRequest(ctx context.Context, streamsLookup *StreamsLookup, pluginRetryKey string) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) + // DoRequest makes a data stream request, it manages retries and returns the following: + // state: the state of the pipeline execution. This field is coupled with err. If state is NoPipelineError then err is nil, otherwise err is non nil and appropriate state is returned + // data: the data returned from the data stream if there's NoPipelineError + // errCode: the errorCode of streams request if data is nil and there's NoPipelineError + // retryable: whether the request is retryable. Only applicable for errored states. + // retryInterval: the interval to wait before retrying the request. Only applicable for errored states. + // err: non nil if some internal error occurs in pipeline + DoRequest(ctx context.Context, streamsLookup *StreamsLookup, upkeepType automationTypes.UpkeepType, pluginRetryKey string) (encoding.PipelineExecutionState, [][]byte, encoding.ErrCode, bool, time.Duration, error) } type StreamsLookupError struct { @@ -121,6 +135,7 @@ type Packer interface { PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) + PackUserCheckErrorHandler(errCode encoding.ErrCode, extraData []byte) ([]byte, error) } type abiPacker struct { @@ -178,3 +193,9 @@ func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) } + +func (p *abiPacker) PackUserCheckErrorHandler(errCode encoding.ErrCode, extraData []byte) ([]byte, error) { + // Convert errCode to bigInt as contract expects uint256 + errCodeBigInt := new(big.Int).SetUint64(uint64(errCode)) + return p.streamsABI.Pack("checkErrorHandler", errCodeBigInt, extraData) +} 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 ce82ec7ae8f..43587f3fe11 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 @@ -5,12 +5,17 @@ import ( "errors" "math/big" "testing" + "time" + "github.com/patrickmn/go-cache" "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/chainlink-common/pkg/types" + + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) @@ -240,3 +245,127 @@ func TestPacker_UnpackCheckCallbackResult(t *testing.T) { }) } } + +func TestPacker_PackUserCheckErrorHandler(t *testing.T) { + tests := []struct { + name string + errCode encoding.ErrCode + extraData []byte + rawOutput []byte + errored bool + }{ + { + name: "happy path", + errCode: encoding.ErrCodeStreamsBadRequest, + extraData: func() []byte { + b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") + + return b + }(), + rawOutput: []byte{0xf, 0xb1, 0x72, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x55, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x19, 0xd9, 0x7a, 0x94, 0x73, 0x7c, 0x95, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xea, 0x8e, 0xd6, 0xd0, 0x61, 0x7d, 0xd5, 0xb3, 0xb8, 0x73, 0x74, 0x2, 0xe, 0xfa, 0xf0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + errored: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer := NewAbiPacker() + + b, err := packer.PackUserCheckErrorHandler(test.errCode, test.extraData) + + if !test.errored { + require.NoError(t, err, "no error expected from packing") + + assert.Equal(t, test.rawOutput, b, "raw bytes for output should match expected") + } else { + assert.NotNil(t, err, "error expected from packing function") + } + }) + } +} + +func Test_CalculateRetryConfigFn(t *testing.T) { + tests := []struct { + name string + times int + upkeepType automationTypes.UpkeepType + expected time.Duration + }{ + { + name: "first retry", + times: 1, + upkeepType: automationTypes.LogTrigger, + expected: 1 * time.Second, + }, + { + name: "second retry", + times: 2, + upkeepType: automationTypes.LogTrigger, + expected: 1 * time.Second, + }, + { + name: "fifth retry", + times: 5, + upkeepType: automationTypes.LogTrigger, + expected: 1 * time.Second, + }, + { + name: "sixth retry", + times: 6, + upkeepType: automationTypes.LogTrigger, + expected: 5 * time.Second, + }, + { + name: "timeout", + times: totalMediumPluginRetries + 1, + upkeepType: automationTypes.LogTrigger, + expected: RetryIntervalTimeout, + }, + { + name: "conditional first timeout", + times: 1, + upkeepType: automationTypes.ConditionTrigger, + expected: RetryIntervalTimeout, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + cfg := newMercuryConfigMock() + var result time.Duration + for i := 0; i < tc.times; i++ { + result = CalculateStreamsRetryConfigFn(tc.upkeepType, "prk", cfg) + } + assert.Equal(t, tc.expected, result) + }) + } +} + +type mercuryConfigMock struct { + pluginRetryCache *cache.Cache +} + +func newMercuryConfigMock() *mercuryConfigMock { + return &mercuryConfigMock{ + pluginRetryCache: cache.New(10*time.Second, time.Minute), + } +} + +func (c *mercuryConfigMock) Credentials() *types.MercuryCredentials { + return nil +} + +func (c *mercuryConfigMock) IsUpkeepAllowed(k string) (interface{}, bool) { + return nil, false +} + +func (c *mercuryConfigMock) SetUpkeepAllowed(k string, v interface{}, d time.Duration) { +} + +func (c *mercuryConfigMock) GetPluginRetry(k string) (interface{}, bool) { + return c.pluginRetryCache.Get(k) +} + +func (c *mercuryConfigMock) SetPluginRetry(k string, v interface{}, d time.Duration) { + c.pluginRetryCache.Set(k, v, d) +} 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 6f0bf98f83d..a63c15408a5 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 @@ -90,7 +90,7 @@ func NewStreamsLookup( } } -// Lookup looks through check upkeep results looking for any that need off chain lookup +// Lookup looks through check upkeep results to find any that needs off chain lookup func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckResult) []ocr2keepers.CheckResult { lookups := map[int]*mercury.StreamsLookup{} for i, checkResult := range checkResults { @@ -101,7 +101,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe for i, lookup := range lookups { wg.Add(1) func(i int, lookup *mercury.StreamsLookup) { - s.threadCtrl.Go(func(ctx context.Context) { + s.threadCtrl.GoCtx(ctx, func(ctx context.Context) { s.doLookup(ctx, &wg, lookup, i, checkResults) }) }(i, lookup) @@ -138,12 +138,6 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper return } - if len(streamsLookupResponse.Feeds) == 0 { - 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, so no need to check here if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 @@ -174,15 +168,27 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper lookups[i] = streamsLookupResponse } +// Does the requested lookup and sets appropriate fields on checkResult[i] func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { defer wg.Done() - values, err := s.DoMercuryRequest(ctx, lookup, checkResults, i) + values, errCode, 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()) + return + } + + if errCode != encoding.ErrCodeNil { + err = s.CheckErrorHandler(ctx, errCode, lookup, checkResults, i) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s CheckErrorHandler err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + } + return } - if err := s.CheckCallback(ctx, values, lookup, checkResults, i); err != nil { + // Mercury request returned values or user's checkErrorhandler didn't return error, call checkCallback + err = s.CheckCallback(ctx, values, lookup, checkResults, i) + if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) } } @@ -195,69 +201,92 @@ func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *me return err } - var mercuryBytes hexutil.Bytes + return s.makeCallbackEthCall(ctx, payload, lookup, checkResults, i) +} + +// eth_call to checkCallback and checkErrorHandler and update checkResults[i] accordingly +func (s *streams) makeCallbackEthCall(ctx context.Context, payload []byte, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { + var responseBytes 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 { + if err := s.client.CallContext(ctx, &responseBytes, "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)) + s.lggr.Infof("at block %d upkeep %s requested time %s responseBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(responseBytes)) - unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) + unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(responseBytes) 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 - } + s.lggr.Infof("at block %d upkeep %s requested time %s returns needed: %v, failure reason: %d, perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, needed, failureReason, hexutil.Encode(performData)) - checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonNone) - checkResults[i].Eligible = true + checkResults[i].IneligibilityReason = uint8(failureReason) + checkResults[i].Eligible = needed 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) +// Does the mercury request for the checkResult. Returns either the looked up values or an error code if something is wrong with mercury +// In case of any pipeline processing issues, returns an error and also sets approriate state on the checkResult itself +func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) ([][]byte, encoding.ErrCode, error) { + var state, values, errCode, retryable, retryInterval = encoding.NoPipelineError, [][]byte{}, encoding.ErrCodeNil, false, 0 * time.Second + var err error pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) + upkeepType := core.GetUpkeepType(checkResults[i].UpkeepID) if lookup.IsMercuryV02() { - state, reason, values, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, pluginRetryKey) + state, values, errCode, retryable, retryInterval, err = s.v02Client.DoRequest(ctx, lookup, upkeepType, pluginRetryKey) } else if lookup.IsMercuryV03() { - state, reason, values, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, pluginRetryKey) + state, values, errCode, retryable, retryInterval, err = s.v03Client.DoRequest(ctx, lookup, upkeepType, pluginRetryKey) } if err != nil { + // Something went wrong in the pipeline processing, set the state, retry reason and return checkResults[i].Retryable = retryable checkResults[i].RetryInterval = retryInterval checkResults[i].PipelineExecutionState = uint8(state) - checkResults[i].IneligibilityReason = uint8(reason) - return nil, err + s.lggr.Debugf("at block %d upkeep %s requested time %s doMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + return nil, encoding.ErrCodeNil, err + } + + if errCode != encoding.ErrCodeNil { + s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest error code: %d", lookup.Block, lookup.UpkeepId, lookup.Time, errCode) + return nil, errCode, nil } for j, v := range values { s.lggr.Infof("at block %d upkeep %s requested time %s doMercuryRequest values[%d]: %s", lookup.Block, lookup.UpkeepId, lookup.Time, j, hexutil.Encode(v)) } - return values, nil + return values, encoding.ErrCodeNil, nil +} + +func (s *streams) CheckErrorHandler(ctx context.Context, errCode encoding.ErrCode, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { + s.lggr.Debugf("at block %d upkeep %s requested time %s CheckErrorHandler error code: %d", lookup.Block, lookup.UpkeepId, lookup.Time, errCode) + + userPayload, err := s.packer.PackUserCheckErrorHandler(errCode, lookup.ExtraData) + if err != nil { + checkResults[i].Retryable = false + checkResults[i].PipelineExecutionState = uint8(encoding.PackUnpackDecodeFailed) + return err + } + + payload, err := s.abi.Pack("executeCallback", lookup.UpkeepId, userPayload) + if err != nil { + checkResults[i].Retryable = false + checkResults[i].PipelineExecutionState = uint8(encoding.PackUnpackDecodeFailed) + return err + } + + return s.makeCallbackEthCall(ctx, payload, lookup, checkResults, i) } // AllowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if @@ -300,7 +329,7 @@ func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s var privilegeConfig UpkeepPrivilegeConfig if err = json.Unmarshal(upkeepPrivilegeConfigBytes, &privilegeConfig); err != nil { - return encoding.MercuryUnmarshalError, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) + return encoding.PrivilegeConfigUnmarshalError, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) } s.mercuryConfig.SetUpkeepAllowed(upkeepId.String(), privilegeConfig.MercuryEnabled, cache.DefaultExpiration) 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 531a97159f1..e67540a7f2b 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 @@ -3,6 +3,7 @@ package streams import ( "bytes" "encoding/json" + "errors" "fmt" "io" "math/big" @@ -11,27 +12,26 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "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" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" 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/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" ) type MockMercuryConfigProvider struct { @@ -118,6 +118,151 @@ func setupStreams(t *testing.T) *streams { return streams } +func TestStreams_CheckErrorHandler(t *testing.T) { + upkeepId := big.NewInt(123456789) + blockNumber := uint64(999) + tests := []struct { + name string + lookup *mercury.StreamsLookup + checkResults []ocr2keepers.CheckResult + errCode encoding.ErrCode + + callbackResp []byte + callbackErr error + + upkeepNeeded bool + performData []byte + wantErr assert.ErrorAssertionFunc + + state encoding.PipelineExecutionState + retryable bool + }{ + { + name: "success - empty extra data", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(100), + ExtraData: []byte{48, 120, 48, 48}, + }, + UpkeepId: upkeepId, + Block: blockNumber, + }, + checkResults: []ocr2keepers.CheckResult{ + {}, + }, + errCode: encoding.ErrCodeNil, + 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, 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, 4, 48, 120, 48, 48, 0, 0, 0, 0, 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{48, 120, 48, 48}, + wantErr: assert.NoError, + }, + { + name: "success - with extra data", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(18952430), + // this is the address of precompile contract ArbSys(0x0000000000000000000000000000000000000064) + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + Block: blockNumber, + }, + checkResults: []ocr2keepers.CheckResult{ + {}, + }, + errCode: encoding.ErrCodeNil, + 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, 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, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 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, 100}, + wantErr: assert.NoError, + }, + { + name: "failure - checkCallback eth_call failure", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(100), + ExtraData: []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, 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, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + UpkeepId: upkeepId, + Block: blockNumber, + }, + checkResults: []ocr2keepers.CheckResult{ + {}, + }, + errCode: encoding.ErrCodeNil, + callbackResp: []byte{}, + callbackErr: errors.New("bad response"), + wantErr: assert.Error, + state: encoding.RpcFlakyFailure, + retryable: true, + upkeepNeeded: false, + }, + { + name: "failure - unpack error because of invalid response bytes from checkCallback eth_call", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(100), + ExtraData: []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, 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, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + UpkeepId: upkeepId, + Block: blockNumber, + }, + checkResults: []ocr2keepers.CheckResult{ + {}, + }, + errCode: encoding.ErrCodeNil, + callbackResp: []byte{0x01, 0xAB, 0x45, 0xFF, 0x32}, // invalid response bytes + wantErr: assert.Error, + state: encoding.PackUnpackDecodeFailed, + retryable: false, + upkeepNeeded: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := new(evmClientMocks.Client) + s := setupStreams(t) + defer s.Close() + + userPayload, err := s.packer.PackUserCheckErrorHandler(tt.errCode, tt.lookup.ExtraData) + require.Nil(t, err) + payload, err := s.abi.Pack("executeCallback", tt.lookup.UpkeepId, userPayload) + require.Nil(t, err) + + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + client.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", args, hexutil.EncodeUint64(tt.lookup.Block)).Return(tt.callbackErr). + Run(func(args mock.Arguments) { + by := args.Get(1).(*hexutil.Bytes) + *by = tt.callbackResp + }).Once() + s.client = client + + err = s.CheckErrorHandler(testutils.Context(t), tt.errCode, tt.lookup, tt.checkResults, 0) + tt.wantErr(t, err, fmt.Sprintf("Error assertion failed: %v", tt.name)) + assert.Equal(t, uint8(tt.state), tt.checkResults[0].PipelineExecutionState) + assert.Equal(t, tt.retryable, tt.checkResults[0].Retryable) + assert.Equal(t, tt.upkeepNeeded, tt.checkResults[0].Eligible) + assert.Equal(t, tt.performData, tt.checkResults[0].PerformData) + }) + } +} + func TestStreams_CheckCallback(t *testing.T) { upkeepId := big.NewInt(123456789) bn := uint64(999) @@ -246,12 +391,9 @@ func TestStreams_CheckCallback(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := setupStreams(t) - defer r.Close() - r.registry = tt.registry - client := new(evmClientMocks.Client) s := setupStreams(t) + defer s.Close() payload, err := s.abi.Pack("checkCallback", tt.lookup.UpkeepId, values, tt.lookup.ExtraData) require.Nil(t, err) args := map[string]interface{}{ @@ -269,6 +411,7 @@ func TestStreams_CheckCallback(t *testing.T) { 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) + assert.Equal(t, tt.upkeepNeeded, tt.input[0].Eligible) }) } } @@ -341,7 +484,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: encoding.MercuryUnmarshalError, + state: encoding.PrivilegeConfigUnmarshalError, config: []byte{0, 1}, registry: &mockRegistry{ GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go new file mode 100644 index 00000000000..df64cf3bcee --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go @@ -0,0 +1,72 @@ +package mercury + +import ( + "net/http" + "net/http/httptest" + "sync/atomic" +) + +type MercuryEndpointMock interface { + URL() string + Username() string + Password() string + CallCount() int + RegisterHandler(http.HandlerFunc) +} + +var _ MercuryEndpointMock = &SimulatedMercuryServer{} + +var notFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) +}) + +type SimulatedMercuryServer struct { + server *httptest.Server + handler http.HandlerFunc + + callCounter atomic.Int32 +} + +func NewSimulatedMercuryServer() *SimulatedMercuryServer { + srv := &SimulatedMercuryServer{ + handler: notFoundHandler, + callCounter: atomic.Int32{}, + } + + srv.server = httptest.NewUnstartedServer(srv) + + return srv +} + +func (ms *SimulatedMercuryServer) URL() string { + return ms.server.URL +} + +func (ms *SimulatedMercuryServer) Username() string { + return "username1" +} + +func (ms *SimulatedMercuryServer) Password() string { + return "password1" +} + +func (ms *SimulatedMercuryServer) CallCount() int { + return int(ms.callCounter.Load()) +} + +func (ms *SimulatedMercuryServer) RegisterHandler(h http.HandlerFunc) { + ms.handler = h +} + +func (ms *SimulatedMercuryServer) Start() { + ms.server.Start() +} + +func (ms *SimulatedMercuryServer) Stop() { + ms.server.Close() +} + +func (ms *SimulatedMercuryServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ms.callCounter.Add(1) + ms.handler.ServeHTTP(w, r) +} 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 202661145bf..6b612a3f350 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 @@ -11,11 +11,13 @@ import ( "strconv" "time" - "github.com/avast/retry-go/v4" - "github.com/ethereum/go-ethereum/common/hexutil" + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/avast/retry-go/v4" + "github.com/ethereum/go-ethereum/common/hexutil" + "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" @@ -53,45 +55,88 @@ func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.H } } -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) +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, upkeepType automationTypes.UpkeepType, pluginRetryKey string) (encoding.PipelineExecutionState, [][]byte, encoding.ErrCode, bool, time.Duration, error) { if len(streamsLookup.Feeds) == 0 { - 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) + return encoding.NoPipelineError, nil, encoding.ErrCodeStreamsBadRequest, false, 0 * time.Second, nil } + resultLen := len(streamsLookup.Feeds) + ch := make(chan mercury.MercuryData, resultLen) for i := range streamsLookup.Feeds { // TODO (AUTO-7209): limit the number of concurrent requests i := i - c.threadCtrl.Go(func(ctx context.Context) { + c.threadCtrl.GoCtx(ctx, func(ctx context.Context) { c.singleFeedRequest(ctx, ch, i, streamsLookup) }) } + // TODO (AUTO 9090): Understand and fix the use of context.Background() here + reqTimeoutCtx, cancel := context.WithTimeout(context.Background(), mercury.RequestTimeout) + defer cancel() + + state := encoding.NoPipelineError var reqErr error - var retryInterval time.Duration - results := make([][]byte, len(streamsLookup.Feeds)) 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 := encoding.NoPipelineError + allFeedsPipelineSuccess := true + allFeedsReturnedValues := true + var errCode encoding.ErrCode + results := make([][]byte, len(streamsLookup.Feeds)) + // in v0.2, when combining results for multiple feed requests + // if any request resulted in pipeline execution error then use the last execution error as the state + // if no execution errors, then check if any feed returned an error code, if so use the last error code 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 != encoding.NoPipelineError { + select { + case <-reqTimeoutCtx.Done(): + // Request Timed out, return timeout error + c.lggr.Errorf("at block %s upkeep %s, streams lookup v0.2 timed out", streamsLookup.Time.String(), streamsLookup.UpkeepId.String()) + return encoding.NoPipelineError, nil, encoding.ErrCodeStreamsTimeout, false, 0 * time.Second, nil + case m := <-ch: + if m.Error != nil { state = m.State + reqErr = errors.Join(reqErr, m.Error) + retryable = retryable && m.Retryable + if m.ErrCode != encoding.ErrCodeNil { + // Some pipeline errors can get converted to error codes if retries are exhausted + errCode = m.ErrCode + } + allFeedsPipelineSuccess = false + continue } - continue + if m.ErrCode != encoding.ErrCodeNil { + errCode = m.ErrCode + allFeedsReturnedValues = false + continue + } + // Feed request didn't face a pipeline error and didn't return an error code + results[m.Index] = m.Bytes[0] } - results[m.Index] = m.Bytes[0] } - if retryable && !allSuccess { - retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) + + if !allFeedsPipelineSuccess { + // Some feeds faced a pipeline error during execution + // If any error was non retryable then just return the state and error + if !retryable { + return state, nil, errCode, retryable, 0 * time.Second, reqErr + } + // If errors were retryable then calculate retry interval + retryInterval := mercury.CalculateStreamsRetryConfigFn(upkeepType, pluginRetryKey, c.mercuryConfig) + if retryInterval != mercury.RetryIntervalTimeout { + // Return the retyrable state with appropriate retry interval + return state, nil, errCode, retryable, retryInterval, reqErr + } + + // Now we have exhausted all our retries. We treat it as not a pipeline error + // and expose error code to the user + return encoding.NoPipelineError, nil, errCode, false, 0 * time.Second, nil + } + + // All feeds faced no pipeline error + // If any feed request returned an error code, return the error code with empty values, else return the values + if !allFeedsReturnedValues { + return encoding.NoPipelineError, nil, errCode, false, 0 * time.Second, nil } - // only retry when not all successful AND none are not retryable - return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr + + // All success, return the results + return encoding.NoPipelineError, results, encoding.ErrCodeNil, false, 0 * time.Second, nil } func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.MercuryData, index int, sl *mercury.StreamsLookup) { @@ -108,7 +153,8 @@ 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: encoding.InvalidMercuryRequest} + // Not a pipeline error, a bad streams request + ch <- mercury.MercuryData{Index: index, ErrCode: encoding.ErrCodeStreamsBadRequest, Bytes: nil, State: encoding.NoPipelineError} return } @@ -120,6 +166,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 + errCode := encoding.ErrCodeNil state := encoding.NoPipelineError retryable := false sent := false @@ -131,29 +178,55 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur retryable = false 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 = encoding.MercuryFlakyFailure - return err + c.lggr.Errorf("at block %s upkeep %s GET request fails for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds[index], err) + errCode = encoding.ErrCodeStreamsUnknownError + if ctx.Err() != nil { + errCode = encoding.ErrCodeStreamsTimeout + } + ch <- mercury.MercuryData{ + Index: index, + Bytes: nil, + ErrCode: errCode, + State: encoding.NoPipelineError, + } + sent = true + return nil } defer httpResponse.Body.Close() if responseBody, err = io.ReadAll(httpResponse.Body); err != nil { - state = encoding.InvalidMercuryResponse - return err + // Not a pipeline error, a bad streams response, send back error code + ch <- mercury.MercuryData{ + Index: index, + Bytes: nil, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } switch httpResponse.StatusCode { case http.StatusNotFound, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: + // Considered as pipeline error, but if retry attempts go over threshold, is changed upstream to ErrCode 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 = encoding.MercuryFlakyFailure + retryable = true + errCode = encoding.HttpToStreamsErrCode(httpResponse.StatusCode) return errors.New(strconv.FormatInt(int64(httpResponse.StatusCode), 10)) case http.StatusOK: // continue default: - 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]) + // Not considered as a pipeline error, a bad streams response with unknown status code. Send back to user as error code + c.lggr.Errorf("at block %s upkeep %s received unhandled status code %d for feed %s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, sl.Feeds[index]) + ch <- mercury.MercuryData{ + Index: index, + Bytes: nil, + ErrCode: encoding.HttpToStreamsErrCode(httpResponse.StatusCode), + State: encoding.NoPipelineError, + } + sent = true + return nil } c.lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, hexutil.Encode(responseBody)) @@ -161,13 +234,25 @@ 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 = encoding.MercuryUnmarshalError - return err + ch <- mercury.MercuryData{ + Index: index, + Bytes: nil, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } 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 = encoding.InvalidMercuryResponse - return err + ch <- mercury.MercuryData{ + Index: index, + Bytes: nil, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } ch <- mercury.MercuryData{ Index: index, @@ -190,10 +275,11 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur if !sent { ch <- mercury.MercuryData{ Index: index, - Bytes: [][]byte{}, + Bytes: nil, + ErrCode: errCode, + State: state, Retryable: retryable, Error: fmt.Errorf("failed to request feed for %s: %w", sl.Feeds[index], retryErr), - State: state, } } } 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 6c07c383504..c7fd7982904 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,6 +11,8 @@ import ( "testing" "time" + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/ethereum/go-ethereum/common/hexutil" @@ -105,11 +107,14 @@ func TestV02_SingleFeedRequest(t *testing.T) { index int lookup *mercury.StreamsLookup blob string + responseBytes string statusCode int lastStatusCode int retryNumber int retryable bool errorMessage string + streamsErrCode encoding.ErrCode + state encoding.PipelineExecutionState }{ { name: "success - mercury responds in the first try", @@ -174,9 +179,69 @@ func TestV02_SingleFeedRequest(t *testing.T) { blob: "0xab2123dc", retryNumber: totalAttempt, statusCode: http.StatusNotFound, + state: encoding.MercuryFlakyFailure, retryable: true, errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: 404\n#3: 404", }, + { + name: "failure StatusGatewayTimeout - returns retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + retryNumber: totalAttempt, + statusCode: http.StatusGatewayTimeout, + state: encoding.MercuryFlakyFailure, + retryable: true, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 504\n#2: 504\n#3: 504", + }, + { + name: "failure StatusServiceUnavailable - returns retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + retryNumber: totalAttempt, + statusCode: http.StatusServiceUnavailable, + streamsErrCode: encoding.ErrCodeStreamsServiceUnavailable, + state: encoding.MercuryFlakyFailure, + retryable: true, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 503\n#2: 503\n#3: 503", + }, + { + name: "failure StatusBadGateway - returns retryable", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xab2123dc", + retryNumber: totalAttempt, + statusCode: http.StatusBadGateway, + streamsErrCode: encoding.ErrCodeStreamsBadGateway, + state: encoding.MercuryFlakyFailure, + retryable: true, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 502\n#2: 502\n#3: 502", + }, { name: "failure - returns retryable and then non-retryable", index: 0, @@ -193,7 +258,7 @@ func TestV02_SingleFeedRequest(t *testing.T) { retryNumber: 1, statusCode: http.StatusNotFound, lastStatusCode: http.StatusTooManyRequests, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 404\n#2: at block 123456 upkeep 123456789 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + streamsErrCode: encoding.ErrCodeStreamsUnknownError, }, { name: "failure - returns not retryable", @@ -207,9 +272,40 @@ func TestV02_SingleFeedRequest(t *testing.T) { }, UpkeepId: upkeepId, }, - blob: "0xab2123dc", - statusCode: http.StatusConflict, - errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 409 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + blob: "0xab2123dc", + statusCode: http.StatusConflict, + streamsErrCode: encoding.ErrCodeStreamsUnknownError, + errorMessage: "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 123456 upkeep 123456789 received status code 409 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + }, + { + name: "failure invalid json response - returns err code", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + responseBytes: "invalid response", + streamsErrCode: encoding.ErrCodeStreamsBadResponse, + }, + { + name: "failure invalid blob - returns err code", + index: 0, + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + blob: "0xgz", // Invalid hex + streamsErrCode: encoding.ErrCodeStreamsBadResponse, }, } @@ -223,6 +319,10 @@ func TestV02_SingleFeedRequest(t *testing.T) { b, err := json.Marshal(mr) assert.Nil(t, err) + if tt.responseBytes != "" { + b = []byte(tt.responseBytes) + } + if tt.retryNumber == 0 { if tt.errorMessage != "" { resp := &http.Response{ @@ -264,9 +364,13 @@ func TestV02_SingleFeedRequest(t *testing.T) { m := <-ch assert.Equal(t, tt.index, m.Index) assert.Equal(t, tt.retryable, m.Retryable) - if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { + assert.Equal(t, tt.state, m.State) + if tt.streamsErrCode != encoding.ErrCodeNil { + assert.Equal(t, tt.streamsErrCode, m.ErrCode) + assert.Equal(t, [][]byte(nil), m.Bytes) + } else if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { assert.Equal(t, tt.errorMessage, m.Error.Error()) - assert.Equal(t, [][]byte{}, m.Bytes) + assert.Equal(t, [][]byte(nil), m.Bytes) } else { blobBytes, err := hexutil.Decode(tt.blob) assert.Nil(t, err) @@ -279,20 +383,20 @@ func TestV02_SingleFeedRequest(t *testing.T) { func TestV02_DoMercuryRequestV02(t *testing.T) { upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) - + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" tests := []struct { name string lookup *mercury.StreamsLookup mockHttpStatusCode int mockChainlinkBlobs []string pluginRetries int - pluginRetryKey string + upkeepType automationTypes.UpkeepType + expectedState encoding.PipelineExecutionState expectedValues [][]byte + expectedErrCode encoding.ErrCode expectedRetryable bool expectedRetryInterval time.Duration expectedError error - state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason }{ { name: "success", @@ -312,6 +416,50 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { expectedRetryable: false, expectedError: nil, }, + { + name: "failure - retryable but out of retries for conditional", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + upkeepType: automationTypes.ConditionTrigger, + mockHttpStatusCode: http.StatusInternalServerError, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte(nil), + expectedRetryable: false, + pluginRetries: 0, + expectedRetryInterval: 0 * time.Second, + expectedErrCode: encoding.ErrCodeStreamsInternalError, + expectedState: encoding.NoPipelineError, + }, + { + name: "failure - retryable but out of retries for conditional 404 error code", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + }, + upkeepType: automationTypes.ConditionTrigger, + mockHttpStatusCode: http.StatusNotFound, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte(nil), + expectedRetryable: false, + pluginRetries: 0, + expectedRetryInterval: 0 * time.Second, + expectedErrCode: encoding.ErrCodeStreamsNotFound, + expectedState: encoding.NoPipelineError, + }, { name: "failure - retryable and interval is 1s", lookup: &mercury.StreamsLookup{ @@ -324,14 +472,16 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, UpkeepId: upkeepId, }, + upkeepType: automationTypes.LogTrigger, + pluginRetries: 1, mockHttpStatusCode: http.StatusInternalServerError, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, + expectedValues: [][]byte(nil), expectedRetryable: true, - pluginRetries: 0, expectedRetryInterval: 1 * time.Second, + expectedErrCode: encoding.ErrCodeStreamsInternalError, + expectedState: encoding.MercuryFlakyFailure, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: encoding.MercuryFlakyFailure, }, { name: "failure - retryable and interval is 5s", @@ -345,14 +495,16 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, UpkeepId: upkeepId, }, + upkeepType: automationTypes.LogTrigger, pluginRetries: 5, mockHttpStatusCode: http.StatusInternalServerError, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, + expectedValues: [][]byte(nil), expectedRetryable: true, expectedRetryInterval: 5 * time.Second, + expectedErrCode: encoding.ErrCodeStreamsInternalError, + expectedState: encoding.MercuryFlakyFailure, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: encoding.MercuryFlakyFailure, }, { name: "failure - not retryable because there are many plugin retries already", @@ -366,16 +518,18 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, UpkeepId: upkeepId, }, - pluginRetries: 10, - mockHttpStatusCode: http.StatusInternalServerError, - mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - 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: encoding.MercuryFlakyFailure, + upkeepType: automationTypes.LogTrigger, + pluginRetries: 6, + mockHttpStatusCode: http.StatusBadGateway, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte(nil), + expectedRetryInterval: 0 * time.Second, + expectedErrCode: encoding.ErrCodeStreamsBadGateway, + expectedRetryable: false, + expectedState: encoding.NoPipelineError, }, { - name: "failure - not retryable", + name: "failure - not retryable with an error code", lookup: &mercury.StreamsLookup{ StreamsLookupError: &mercury.StreamsLookupError{ FeedParamKey: mercury.FeedIdHex, @@ -388,10 +542,10 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, mockHttpStatusCode: http.StatusTooManyRequests, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, - expectedValues: [][]byte{nil}, + expectedValues: [][]byte(nil), + expectedErrCode: encoding.ErrCodeStreamsUnknownError, 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: encoding.InvalidMercuryRequest, + expectedState: encoding.NoPipelineError, }, { name: "failure - no feeds", @@ -405,8 +559,8 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, UpkeepId: upkeepId, }, - expectedValues: [][]byte{}, - reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, + expectedValues: [][]byte(nil), + expectedErrCode: encoding.ErrCodeStreamsBadRequest, }, { name: "failure - invalid revert data", @@ -420,8 +574,8 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { }, UpkeepId: upkeepId, }, - expectedValues: [][]byte{}, - reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, + expectedValues: [][]byte(nil), + expectedErrCode: encoding.ErrCodeStreamsBadRequest, }, } @@ -430,7 +584,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { c := setupClient(t) defer c.Close() if tt.pluginRetries != 0 { - c.mercuryConfig.SetPluginRetry(tt.pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) + c.mercuryConfig.SetPluginRetry(pluginRetryKey, tt.pluginRetries, cache.DefaultExpiration) } hc := new(MockHttpClient) @@ -443,7 +597,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { StatusCode: tt.mockHttpStatusCode, Body: io.NopCloser(bytes.NewReader(b)), } - if tt.expectedError != nil && tt.expectedRetryable || tt.pluginRetries > 0 { + if tt.expectedErrCode != encoding.ErrCodeNil { hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) } else { hc.On("Do", mock.Anything).Return(resp, nil).Once() @@ -451,19 +605,256 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { } c.httpClient = hc - state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, tt.pluginRetryKey) + state, values, errCode, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, tt.upkeepType, pluginRetryKey) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) if retryable { - newRetries, _ := c.mercuryConfig.GetPluginRetry(tt.pluginRetryKey) + newRetries, _ := c.mercuryConfig.GetPluginRetry(pluginRetryKey) assert.Equal(t, tt.pluginRetries+1, newRetries.(int)) } assert.Equal(t, tt.expectedRetryInterval, retryInterval) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.reason, reason) + assert.Equal(t, tt.expectedErrCode, errCode) + assert.Equal(t, tt.expectedState, state) + if tt.expectedError != nil { assert.True(t, strings.HasPrefix(reqErr.Error(), "failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000")) } }) } } + +func TestV02_DoMercuryRequestV02_MultipleFeedsSuccess(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + for i := 0; i <= 3; i++ { + mr := MercuryV02Response{ChainlinkBlob: "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, _, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.ConditionTrigger, pluginRetryKey) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeNil, errCode) + assert.Equal(t, encoding.NoPipelineError, state) +} + +func TestV02_DoMercuryRequestV02_Timeout(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + mr := MercuryV02Response{ChainlinkBlob: "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() // First request sends result normally + + resp2 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte{})), + } + // Second request has timeout + serverTimeout := 15 * time.Second // Server has delay of 15s, higher than mercury.RequestTimeout = 10s + hc.On("Do", mock.Anything).Run(func(args mock.Arguments) { + time.Sleep(serverTimeout) + }).Return(resp2, nil).Once() + + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + start := time.Now() + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.ConditionTrigger, pluginRetryKey) + elapsed := time.Since(start) + assert.True(t, elapsed < serverTimeout) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsTimeout, errCode) + assert.Equal(t, encoding.NoPipelineError, state) + assert.Equal(t, [][]byte(nil), values) +} + +func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedPipelineError(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + // First request success + mr := MercuryV02Response{ChainlinkBlob: "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + // Second request returns MercuryFlakyError + resp = &http.Response{ + StatusCode: http.StatusServiceUnavailable, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.LogTrigger, pluginRetryKey) + assert.Equal(t, true, retryable) + assert.Equal(t, 1*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsServiceUnavailable, errCode) + assert.Equal(t, encoding.MercuryFlakyFailure, state) + assert.Equal(t, [][]byte(nil), values) +} + +func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedErrCode(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + // First request success + mr := MercuryV02Response{ChainlinkBlob: "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + // Second request returns invalid response + resp = &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte{})), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.LogTrigger, pluginRetryKey) + assert.Equal(t, [][]byte(nil), values) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsBadResponse, errCode) + assert.Equal(t, encoding.NoPipelineError, state) +} + +func TestV02_DoMercuryRequestV02_OneFeedSuccessOneFeedPipelineErrorConvertedError(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + // First request success + mr := MercuryV02Response{ChainlinkBlob: "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"} + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + // Second request returns MercuryFlakyError + resp = &http.Response{ + StatusCode: http.StatusGatewayTimeout, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.ConditionTrigger, pluginRetryKey) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsStatusGatewayTimeout, errCode) + assert.Equal(t, encoding.NoPipelineError, state) + assert.Equal(t, [][]byte(nil), values) +} 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 584069adde3..8ac8696ddbb 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 @@ -10,11 +10,13 @@ import ( "strings" "time" - "github.com/avast/retry-go/v4" - "github.com/ethereum/go-ethereum/common/hexutil" + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/avast/retry-go/v4" + "github.com/ethereum/go-ethereum/common/hexutil" + "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" @@ -61,35 +63,46 @@ func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.H } } -func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) { +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, upkeepType automationTypes.UpkeepType, pluginRetryKey string) (encoding.PipelineExecutionState, [][]byte, encoding.ErrCode, bool, time.Duration, error) { if len(streamsLookup.Feeds) == 0 { - 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) + return encoding.NoPipelineError, nil, encoding.ErrCodeStreamsBadRequest, false, 0 * time.Second, nil } resultLen := 1 // Only 1 multi-feed request is made for all feeds ch := make(chan mercury.MercuryData, resultLen) - c.threadCtrl.Go(func(ctx context.Context) { + c.threadCtrl.GoCtx(ctx, func(ctx context.Context) { c.multiFeedsRequest(ctx, ch, streamsLookup) }) - var reqErr error - var retryInterval time.Duration - results := make([][]byte, len(streamsLookup.Feeds)) - retryable := false - state := encoding.NoPipelineError + // TODO (AUTO 9090): Understand and fix the use of context.Background() here + reqTimeoutCtx, cancel := context.WithTimeout(context.Background(), mercury.RequestTimeout) + defer cancel() + select { + case <-reqTimeoutCtx.Done(): + // Request Timed out, return timeout error + c.lggr.Errorf("at timestamp %s upkeep %s, streams lookup v0.3 timed out", streamsLookup.Time.String(), streamsLookup.UpkeepId.String()) + return encoding.NoPipelineError, nil, encoding.ErrCodeStreamsTimeout, false, 0 * time.Second, nil + case m := <-ch: + if m.Error != nil { + // There was a pipeline error during execution + // If error was non retryable then just return the state and error + if !m.Retryable { + return m.State, nil, m.ErrCode, m.Retryable, 0 * time.Second, m.Error + } + // If errors were retryable then calculate retry interval + retryInterval := mercury.CalculateStreamsRetryConfigFn(upkeepType, pluginRetryKey, c.mercuryConfig) + if retryInterval != mercury.RetryIntervalTimeout { + // Return the retyrable state with appropriate retry interval + return m.State, nil, m.ErrCode, m.Retryable, retryInterval, m.Error + } - m := <-ch - if m.Error != nil { - reqErr = m.Error - retryable = m.Retryable - state = m.State - if retryable { - retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) + // Now we have exhausted all our retries. We treat it as not a pipeline error + // and expose error code to the user + return encoding.NoPipelineError, nil, m.ErrCode, false, 0 * time.Second, nil } - } else { - results = m.Bytes - } - return state, encoding.UpkeepFailureReasonNone, results, retryable, retryInterval, reqErr + // No pipeline error, return bytes and error code out of which one should be null + return encoding.NoPipelineError, m.Bytes, m.ErrCode, false, 0 * time.Second, nil + } } func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.MercuryData, sl *mercury.StreamsLookup) { @@ -110,7 +123,8 @@ 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: encoding.InvalidMercuryRequest} + // Not a pipeline error, a bad streams request + ch <- mercury.MercuryData{Index: 0, ErrCode: encoding.ErrCodeStreamsBadRequest, State: encoding.NoPipelineError} return } @@ -128,62 +142,100 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur // in the case of multiple retries here, use the last attempt's data state := encoding.NoPipelineError + errCode := encoding.ErrCodeNil retryable := false sent := false + retryCtx, cancel := context.WithCancel(ctx) + defer cancel() retryErr := retry.Do( func() error { retryable = false resp, err := c.httpClient.Do(req) 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 = encoding.MercuryFlakyFailure - return err + c.lggr.Errorf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.Time.String(), sl.UpkeepId.String(), err) + errCode = encoding.ErrCodeStreamsUnknownError + if ctx.Err() != nil { + errCode = encoding.ErrCodeStreamsTimeout + } + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: errCode, + State: encoding.NoPipelineError, + } + sent = true + return nil } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - retryable = false - state = encoding.InvalidMercuryResponse - return err + // Not a pipeline error, a bad streams response, send back error code + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } c.lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) switch resp.StatusCode { case http.StatusUnauthorized: - retryable = false - 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) + c.lggr.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) + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.HttpToStreamsErrCode(resp.StatusCode), + State: encoding.NoPipelineError, + } + sent = true + return nil case http.StatusBadRequest: - retryable = false - 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) + c.lggr.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) + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.HttpToStreamsErrCode(resp.StatusCode), + State: encoding.NoPipelineError, + } + sent = true + return nil case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: retryable = true state = encoding.MercuryFlakyFailure + errCode = encoding.HttpToStreamsErrCode(resp.StatusCode) 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 = encoding.MercuryFlakyFailure + errCode = encoding.HttpToStreamsErrCode(resp.StatusCode) return fmt.Errorf("%d", http.StatusPartialContent) case http.StatusOK: // continue default: - retryable = false - 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) + // Not considered as a pipeline error, a bad streams response with unknown status code. Send back to user as error code + c.lggr.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.HttpToStreamsErrCode(resp.StatusCode), + State: encoding.NoPipelineError, + } + sent = true + return nil } 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)) var response MercuryV03Response 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 = encoding.MercuryUnmarshalError - return err + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract @@ -193,27 +245,31 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur for _, f := range response.Reports { receivedFeeds = append(receivedFeeds, f.FeedID) } - 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) + c.lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned less reports [%s] while we requested [%s] feeds, retrying", sl.Time.String(), sl.UpkeepId.String(), receivedFeeds, sl.Feeds) retryable = true state = encoding.MercuryFlakyFailure - return fmt.Errorf("%d", http.StatusNotFound) + errCode = encoding.HttpToStreamsErrCode(http.StatusPartialContent) + return fmt.Errorf("%d", http.StatusPartialContent) } var reportBytes [][]byte for _, rsp := range response.Reports { b, err := hexutil.Decode(rsp.FullReport) 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 = encoding.InvalidMercuryResponse - return err + ch <- mercury.MercuryData{ + Index: 0, + ErrCode: encoding.ErrCodeStreamsBadResponse, + State: encoding.NoPipelineError, + } + sent = true + return nil } reportBytes = append(reportBytes, b) } ch <- mercury.MercuryData{ - Index: 0, - Bytes: reportBytes, - Retryable: false, - State: encoding.NoPipelineError, + Index: 0, + Bytes: reportBytes, + State: encoding.NoPipelineError, } sent = true return nil @@ -222,7 +278,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur retry.RetryIf(func(err error) bool { return err.Error() == fmt.Sprintf("%d", http.StatusPartialContent) || err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) || err.Error() == fmt.Sprintf("%d", http.StatusBadGateway) || err.Error() == fmt.Sprintf("%d", http.StatusServiceUnavailable) || err.Error() == fmt.Sprintf("%d", http.StatusGatewayTimeout) }), - retry.Context(ctx), + retry.Context(retryCtx), retry.Delay(retryDelay), retry.Attempts(totalAttempt), ) @@ -230,9 +286,10 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur if !sent { ch <- mercury.MercuryData{ Index: 0, - Bytes: [][]byte{}, + Bytes: nil, Retryable: retryable, Error: retryErr, + ErrCode: errCode, State: state, } } 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 a7742c04872..9c0e2aaa147 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,10 +9,13 @@ import ( "testing" "time" + automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -21,8 +24,6 @@ import ( "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" - - "github.com/stretchr/testify/assert" ) const ( @@ -109,9 +110,9 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { expectedValues [][]byte expectedRetryable bool expectedRetryInterval time.Duration + expectedErrCode encoding.ErrCode expectedError error state encoding.PipelineExecutionState - reason encoding.UpkeepFailureReason }{ { name: "success v0.3", @@ -163,13 +164,13 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { } c.httpClient = hc - state, reason, values, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, tt.pluginRetryKey) + state, values, errCode, retryable, retryInterval, reqErr := c.DoRequest(testutils.Context(t), tt.lookup, automationTypes.ConditionTrigger, tt.pluginRetryKey) assert.Equal(t, tt.expectedValues, values) assert.Equal(t, tt.expectedRetryable, retryable) assert.Equal(t, tt.expectedRetryInterval, retryInterval) assert.Equal(t, tt.state, state) - assert.Equal(t, tt.reason, reason) + assert.Equal(t, tt.expectedErrCode, errCode) if tt.expectedError != nil { assert.Equal(t, tt.expectedError.Error(), reqErr.Error()) } @@ -177,6 +178,239 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { } } +func TestV03_DoMercuryRequestV03_MultipleFeedsSuccess(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + for i := 0; i <= 3; i++ { + mr := MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + } + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, _, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.ConditionTrigger, pluginRetryKey) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeNil, errCode) + assert.Equal(t, encoding.NoPipelineError, state) +} + +func TestV03_DoMercuryRequestV03_Timeout(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + mr := MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + } + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + serverTimeout := 15 * time.Second // Server has delay of 15s, higher than mercury.RequestTimeout = 10s + hc.On("Do", mock.Anything).Run(func(args mock.Arguments) { + time.Sleep(serverTimeout) + }).Return(resp, nil).Once() + + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + start := time.Now() + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.ConditionTrigger, pluginRetryKey) + elapsed := time.Since(start) + assert.True(t, elapsed < serverTimeout) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsTimeout, errCode) + assert.Equal(t, encoding.NoPipelineError, state) + assert.Equal(t, [][]byte(nil), values) +} + +func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedPipelineError(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + // First request success + mr := MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + } + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + // Second request returns MercuryFlakyError + resp = &http.Response{ + StatusCode: http.StatusBadGateway, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.LogTrigger, pluginRetryKey) + assert.Equal(t, true, retryable) + assert.Equal(t, 1*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsBadGateway, errCode) + assert.Equal(t, encoding.MercuryFlakyFailure, state) + assert.Equal(t, [][]byte(nil), values) +} + +func TestV03_DoMercuryRequestV03_OneFeedSuccessOneFeedErrCode(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + pluginRetryKey := "88786950015966611018675766524283132478093844178961698330929478019253453382042|34" + + c := setupClient(t) + defer c.Close() + + c.mercuryConfig.SetPluginRetry(pluginRetryKey, 0, cache.DefaultExpiration) + hc := new(MockHttpClient) + + // First request success + mr := MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + } + b, err := json.Marshal(mr) + assert.Nil(t, err) + + resp := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() + + // Second request returns invalid response + invalidResponse := MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "random", // invalid hex + }, + }, + } + b, err = json.Marshal(invalidResponse) + assert.Nil(t, err) + + resp = &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + c.httpClient = hc + + lookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + UpkeepId: upkeepId, + } + + state, values, errCode, retryable, retryInterval, _ := c.DoRequest(testutils.Context(t), lookup, automationTypes.LogTrigger, pluginRetryKey) + assert.Equal(t, [][]byte(nil), values) + assert.Equal(t, false, retryable) + assert.Equal(t, 0*time.Second, retryInterval) + assert.Equal(t, encoding.ErrCodeStreamsBadResponse, errCode) + assert.Equal(t, encoding.NoPipelineError, state) +} + func TestV03_MultiFeedRequest(t *testing.T) { upkeepId := big.NewInt(123456789) tests := []struct { @@ -191,6 +425,8 @@ func TestV03_MultiFeedRequest(t *testing.T) { errorMessage string firstResponse *MercuryV03Response response *MercuryV03Response + streamsErrCode encoding.ErrCode + state encoding.PipelineExecutionState }{ { name: "success - mercury responds in the first try", @@ -323,7 +559,7 @@ func TestV03_MultiFeedRequest(t *testing.T) { }, }, { - name: "failure - fail to decode reportBlob", + name: "failure - invalid response and fail to decode reportBlob", lookup: &mercury.StreamsLookup{ StreamsLookupError: &mercury.StreamsLookupError{ FeedParamKey: mercury.FeedIDs, @@ -349,9 +585,11 @@ func TestV03_MultiFeedRequest(t *testing.T) { }, }, }, - statusCode: http.StatusOK, - retryable: false, - errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", + statusCode: http.StatusOK, + retryable: false, + errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", + streamsErrCode: encoding.ErrCodeStreamsBadResponse, + state: encoding.NoPipelineError, }, { name: "failure - returns retryable with 1s plugin retry interval", @@ -400,7 +638,8 @@ func TestV03_MultiFeedRequest(t *testing.T) { retryNumber: 1, statusCode: http.StatusInternalServerError, lastStatusCode: http.StatusUnauthorized, - errorMessage: "All attempts fail:\n#1: 500\n#2: at timestamp 123456 upkeep 123456789 received status code 401 from mercury v0.3, most likely this is caused by unauthorized upkeep", + streamsErrCode: encoding.ErrCodeStreamsUnauthorized, + state: encoding.NoPipelineError, }, { name: "failure - returns status code 422 not retryable", @@ -413,8 +652,119 @@ func TestV03_MultiFeedRequest(t *testing.T) { }, UpkeepId: upkeepId, }, - statusCode: http.StatusUnprocessableEntity, - errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 422 from mercury v0.3", + statusCode: http.StatusUnprocessableEntity, + streamsErrCode: encoding.ErrCodeStreamsUnknownError, + state: encoding.NoPipelineError, + }, + { + name: "failure - StatusGatewayTimeout - returns retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: totalAttempt, + statusCode: http.StatusGatewayTimeout, + state: encoding.MercuryFlakyFailure, + retryable: true, + streamsErrCode: encoding.ErrCodeStreamsStatusGatewayTimeout, + errorMessage: "All attempts fail:\n#1: 504\n#2: 504\n#3: 504", + }, + { + name: "failure - StatusServiceUnavailable - returns retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: totalAttempt, + statusCode: http.StatusServiceUnavailable, + state: encoding.MercuryFlakyFailure, + retryable: true, + streamsErrCode: encoding.ErrCodeStreamsServiceUnavailable, + errorMessage: "All attempts fail:\n#1: 503\n#2: 503\n#3: 503", + }, + { + name: "failure - StatusBadGateway - returns retryable", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.Timestamp, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + retryNumber: totalAttempt, + statusCode: http.StatusBadGateway, + streamsErrCode: encoding.ErrCodeStreamsBadGateway, + state: encoding.MercuryFlakyFailure, + retryable: true, + errorMessage: "All attempts fail:\n#1: 502\n#2: 502\n#3: 502", + }, + + { + name: "failure - partial content three times with status ok", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + }, + statusCode: http.StatusOK, + retryNumber: totalAttempt, + retryable: true, + streamsErrCode: encoding.ErrCodeStreamsPartialContent, + errorMessage: "All attempts fail:\n#1: 404\n#2: 404\n#3: 404", + state: encoding.MercuryFlakyFailure, + }, + { + name: "failure - partial content three times with status partial content", + lookup: &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: mercury.FeedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: mercury.BlockNumber, + Time: big.NewInt(123456), + }, + UpkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + }, + }, + statusCode: http.StatusPartialContent, + retryNumber: totalAttempt, + retryable: true, + errorMessage: "All attempts fail:\n#1: 206\n#2: 206\n#3: 206", + state: encoding.MercuryFlakyFailure, }, { name: "success - retry when reports length does not match feeds length", @@ -506,11 +856,13 @@ func TestV03_MultiFeedRequest(t *testing.T) { hc.On("Do", mock.Anything).Return(resp, nil).Once() } } else { - resp := &http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(b)), + for i := 1; i <= tt.retryNumber; i++ { + resp := &http.Response{ + StatusCode: tt.statusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + hc.On("Do", mock.Anything).Return(resp, nil).Once() } - hc.On("Do", mock.Anything).Return(resp, nil).Times(tt.retryNumber) } c.httpClient = hc @@ -520,9 +872,13 @@ func TestV03_MultiFeedRequest(t *testing.T) { m := <-ch assert.Equal(t, 0, m.Index) assert.Equal(t, tt.retryable, m.Retryable) - if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { + if tt.streamsErrCode != encoding.ErrCodeNil { + assert.Equal(t, tt.streamsErrCode, m.ErrCode) + assert.Equal(t, tt.state, m.State) + assert.Equal(t, [][]byte(nil), m.Bytes) + } else if tt.retryNumber >= totalAttempt || tt.errorMessage != "" { assert.Equal(t, tt.errorMessage, m.Error.Error()) - assert.Equal(t, [][]byte{}, m.Bytes) + assert.Equal(t, [][]byte(nil), m.Bytes) } else { assert.Nil(t, m.Error) var reports [][]byte 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 6475b3ef7df..6a09ae1aca3 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 @@ -45,7 +45,7 @@ func (r *EvmRegistry) CheckUpkeeps(ctx context.Context, keys ...ocr2keepers.Upke chResult := make(chan checkResult, 1) - r.threadCtrl.Go(func(ctx context.Context) { + r.threadCtrl.GoCtx(ctx, func(ctx context.Context) { r.doCheck(ctx, keys, chResult) }) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 81a35a5ced2..4aa9b0cb7dc 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -2,7 +2,7 @@ package ocr2keeper_test import ( "context" - "crypto/rand" + crand "crypto/rand" "encoding/hex" "encoding/json" "fmt" @@ -10,6 +10,7 @@ import ( "net/http" "strings" "sync" + "sync/atomic" "testing" "time" @@ -53,13 +54,14 @@ 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/ocr2/plugins/ocr2keeper" + "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/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) func TestFilterNamesFromSpec21(t *testing.T) { b := make([]byte, 20) - _, err := rand.Read(b) + _, err := crand.Read(b) require.NoError(t, err) address := common.HexToAddress(hexutil.Encode(b)) @@ -352,7 +354,9 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { // deploy multiple upkeeps that listen to a log emitter and need to be // performed for each log event - _ = feeds.DeployUpkeeps(t, backend, upkeepOwner, upkeepCount) + _ = feeds.DeployUpkeeps(t, backend, upkeepOwner, upkeepCount, func(int) bool { + return false + }) _ = feeds.RegisterAndFund(t, registry, registryOwner, backend, linkToken) _ = feeds.EnableMercury(t, backend, registry, registryOwner) _ = feeds.VerifyEnv(t, backend, registry, registryOwner) @@ -374,6 +378,138 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { done() } +func TestIntegration_KeeperPluginLogUpkeep_ErrHandler(t *testing.T) { + g := gomega.NewWithT(t) + + // setup blockchain + linkOwner := testutils.MustNewSimTransactor(t) // owns all the link + registryOwner := testutils.MustNewSimTransactor(t) // registry owner + upkeepOwner := testutils.MustNewSimTransactor(t) // upkeep owner + genesisData := core.GenesisAlloc{ + linkOwner.From: {Balance: assets.Ether(10000).ToInt()}, + registryOwner.From: {Balance: assets.Ether(10000).ToInt()}, + upkeepOwner.From: {Balance: assets.Ether(10000).ToInt()}, + } + + // Generate 5 keys for nodes (1 bootstrap + 4 ocr nodes) and fund them with ether + var nodeKeys [5]ethkey.KeyV2 + for i := int64(0); i < 5; i++ { + nodeKeys[i] = cltest.MustGenerateRandomKey(t) + genesisData[nodeKeys[i].Address] = core.GenesisAccount{Balance: assets.Ether(1000).ToInt()} + } + + backend := cltest.NewSimulatedBackend(t, genesisData, uint32(ethconfig.Defaults.Miner.GasCeil)) + stopMining := cltest.Mine(backend, 3*time.Second) // Should be greater than deltaRound since we cannot access old blocks on simulated blockchain + defer stopMining() + + // Deploy registry + linkAddr, _, linkToken, err := link_token_interface.DeployLinkToken(linkOwner, backend) + require.NoError(t, err) + + gasFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(registryOwner, backend, 18, big.NewInt(60000000000)) + require.NoError(t, err) + + linkFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(registryOwner, backend, 18, big.NewInt(2000000000000000000)) + require.NoError(t, err) + + registry := deployKeeper21Registry(t, registryOwner, backend, linkAddr, linkFeedAddr, gasFeedAddr) + + _, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) + + upkeepCount := 10 + + errResponses := []int{ + http.StatusUnauthorized, + http.StatusBadRequest, + http.StatusInternalServerError, + } + startMercuryServer(t, mercuryServer, func(i int) (int, []byte) { + var resp int + if i < len(errResponses) { + resp = errResponses[i] + } + if resp == 0 { + resp = http.StatusNotFound + } + return resp, nil + }) + defer mercuryServer.Stop() + + _, err = linkToken.Transfer(linkOwner, upkeepOwner.From, big.NewInt(0).Mul(oneHunEth, big.NewInt(int64(upkeepCount+1)))) + require.NoError(t, err) + + backend.Commit() + + feeds, err := newFeedLookupUpkeepController(backend, registryOwner) + require.NoError(t, err, "no error expected from creating a feed lookup controller") + + // deploy multiple upkeeps that listen to a log emitter and need to be + // performed for each log event + checkResultsProvider := func(i int) bool { + return i%2 == 1 + } + require.NoError(t, feeds.DeployUpkeeps(t, backend, upkeepOwner, upkeepCount, checkResultsProvider)) + require.NoError(t, feeds.RegisterAndFund(t, registry, registryOwner, backend, linkToken)) + require.NoError(t, feeds.EnableMercury(t, backend, registry, registryOwner)) + require.NoError(t, feeds.VerifyEnv(t, backend, registry, registryOwner)) + + startBlock := backend.Blockchain().CurrentBlock().Number.Int64() + // start emitting events in a separate go-routine + // feed lookup relies on a single contract event log to perform multiple + // listener contracts + go func() { + // only 1 event is necessary to make all 10 upkeeps eligible + _ = feeds.EmitEvents(t, backend, 1, func() { + // pause per emit for expected block production time + time.Sleep(3 * time.Second) + }) + }() + + go makeDummyBlocks(t, backend, 3*time.Second, 1000) + + idsToCheck := make([]*big.Int, 0) + for i, uid := range feeds.UpkeepsIds() { + if checkResultsProvider(i) { + idsToCheck = append(idsToCheck, uid) + } + } + + listener, done := listenPerformed(t, backend, registry, idsToCheck, startBlock) + g.Eventually(listener, testutils.WaitTimeout(t)-(5*time.Second), cltest.DBPollingInterval).Should(gomega.BeTrue()) + done() +} + +func startMercuryServer(t *testing.T, mercuryServer *mercury.SimulatedMercuryServer, responder func(i int) (int, []byte)) { + i := atomic.Int32{} + mercuryServer.RegisterHandler(func(w http.ResponseWriter, r *http.Request) { + _ = r.ParseForm() + t.Logf("MercuryHTTPServe:RequestURI: %s", r.RequestURI) + for key, value := range r.Form { + t.Logf("MercuryHTTPServe:FormValue: key: %s; value: %s;", key, value) + } + + ii := int(i.Load()) + i.Add(1) + status, body := responder(ii) + w.WriteHeader(status) + if len(body) > 0 { + _, _ = w.Write(body) + } + }) +} + +func makeDummyBlocks(t *testing.T, backend *backends.SimulatedBackend, interval time.Duration, count int) { + go func() { + ctx, cancel := context.WithCancel(testutils.Context(t)) + defer cancel() + + for i := 0; i < count && ctx.Err() == nil; i++ { + backend.Commit() + time.Sleep(interval) + } + }() +} + func emitEvents(ctx context.Context, t *testing.T, n int, contracts []*log_upkeep_counter_wrapper.LogUpkeepCounter, carrol *bind.TransactOpts, afterEmit func()) { for i := 0; i < n && ctx.Err() == nil; i++ { for _, contract := range contracts { @@ -450,9 +586,9 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry 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) { +func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *mercury.SimulatedMercuryServer) { lggr := logger.TestLogger(t) - mServer := NewSimulatedMercuryServer() + mServer := mercury.NewSimulatedMercuryServer() mServer.Start() // Setup bootstrap + oracle nodes @@ -789,17 +925,23 @@ func (c *feedLookupUpkeepController) DeployUpkeeps( backend *backends.SimulatedBackend, owner *bind.TransactOpts, count int, + checkErrResultsProvider func(i int) bool, ) error { addresses := make([]common.Address, count) contracts := make([]*log_triggered_streams_lookup_wrapper.LogTriggeredStreamsLookup, count) // deploy n upkeep contracts for x := 0; x < count; x++ { + var checkErrResult bool + if checkErrResultsProvider != nil { + checkErrResult = checkErrResultsProvider(x) + } addr, _, contract, err := log_triggered_streams_lookup_wrapper.DeployLogTriggeredStreamsLookup( owner, backend, false, false, + checkErrResult, ) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 56467c60abb..937c3df0c36 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -6,10 +6,7 @@ import ( "encoding/json" "fmt" "math/big" - "net/http" - "net/http/httptest" "strings" - "sync" "testing" "time" @@ -57,6 +54,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -112,7 +110,7 @@ func setupNode( nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, - mercury MercuryEndpoint, + mercury mercury.MercuryEndpointMock, ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { p2pKey := keystest.NewP2PKeyV2(t) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} @@ -236,7 +234,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, mercury.NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -250,7 +248,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, NewSimulatedMercuryServer()) + }, mercury.NewSimulatedMercuryServer()) nodes = append(nodes, Node{ app, transmitter, kb, @@ -488,7 +486,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, mercury.NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -503,7 +501,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, NewSimulatedMercuryServer()) + }, mercury.NewSimulatedMercuryServer()) nodeForwarder := setupForwarderForNode(t, app, sergey, backend, transmitter, linkAddr) effectiveTransmitters = append(effectiveTransmitters, nodeForwarder) @@ -711,72 +709,3 @@ func TestFilterNamesFromSpec20(t *testing.T) { _, err = ocr2keeper.FilterNamesFromSpec20(spec) require.ErrorContains(t, err, "not a valid EIP55 formatted address") } - -// ------- below this line could be added to a test helpers package -type MercuryEndpoint interface { - URL() string - Username() string - Password() string - CallCount() int - RegisterHandler(http.HandlerFunc) -} - -type SimulatedMercuryServer struct { - server *httptest.Server - handler http.HandlerFunc - - mu sync.RWMutex - callCount int -} - -func NewSimulatedMercuryServer() *SimulatedMercuryServer { - srv := &SimulatedMercuryServer{ - handler: func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotFound) - }, - } - - srv.server = httptest.NewUnstartedServer(srv) - - return srv -} - -func (ms *SimulatedMercuryServer) URL() string { - return ms.server.URL -} - -func (ms *SimulatedMercuryServer) Username() string { - return "username1" -} - -func (ms *SimulatedMercuryServer) Password() string { - return "password1" -} - -func (ms *SimulatedMercuryServer) CallCount() int { - ms.mu.RLock() - defer ms.mu.RUnlock() - - return ms.callCount -} - -func (ms *SimulatedMercuryServer) RegisterHandler(h http.HandlerFunc) { - ms.handler = h -} - -func (ms *SimulatedMercuryServer) Start() { - ms.server.Start() -} - -func (ms *SimulatedMercuryServer) Stop() { - ms.server.Close() -} - -func (ms *SimulatedMercuryServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - ms.mu.Lock() - defer ms.mu.Unlock() - - ms.callCount++ - - ms.handler.ServeHTTP(w, r) -} diff --git a/core/utils/thread_control.go b/core/utils/thread_control.go index 52cda82797a..ac0047a07ce 100644 --- a/core/utils/thread_control.go +++ b/core/utils/thread_control.go @@ -13,6 +13,8 @@ var _ ThreadControl = &threadControl{} type ThreadControl interface { // Go starts a goroutine and tracks the lifetime of the goroutine. Go(fn func(context.Context)) + // GoCtx starts a goroutine with a given context and tracks the lifetime of the goroutine. + GoCtx(ctx context.Context, fn func(context.Context)) // Close cancels the goroutines and waits for all of them to exit. Close() } @@ -40,6 +42,17 @@ func (tc *threadControl) Go(fn func(context.Context)) { }() } +func (tc *threadControl) GoCtx(ctx context.Context, fn func(context.Context)) { + tc.threadsWG.Add(1) + go func() { + defer tc.threadsWG.Done() + // Create a new context that is cancelled when either parent context is cancelled or stop is closed. + ctx2, cancel := tc.stop.Ctx(ctx) + defer cancel() + fn(ctx2) + }() +} + func (tc *threadControl) Close() { close(tc.stop) tc.threadsWG.Wait() diff --git a/core/utils/thread_control_test.go b/core/utils/thread_control_test.go index 9001ca7241c..dff3740eda7 100644 --- a/core/utils/thread_control_test.go +++ b/core/utils/thread_control_test.go @@ -2,8 +2,10 @@ package utils import ( "context" + "sync" "sync/atomic" "testing" + "time" "github.com/stretchr/testify/require" ) @@ -25,3 +27,29 @@ func TestThreadControl_Close(t *testing.T) { require.Equal(t, int32(n), finished.Load()) } + +func TestThreadControl_GoCtx(t *testing.T) { + tc := NewThreadControl() + defer tc.Close() + + var wg sync.WaitGroup + finished := atomic.Int32{} + + timeout := 10 * time.Millisecond + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + wg.Add(1) + tc.GoCtx(ctx, func(c context.Context) { + defer wg.Done() + <-c.Done() + finished.Add(1) + }) + + start := time.Now() + wg.Wait() + require.True(t, time.Since(start) > timeout-1) + require.True(t, time.Since(start) < 2*timeout) + require.Equal(t, int32(1), finished.Load()) +} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index f53a709779d..fead418fb96 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -1562,7 +1562,7 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggeredStreamsLookupUpke backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return log_triggered_streams_lookup_wrapper.DeployLogTriggeredStreamsLookup( - auth, backend, false, false, + auth, backend, false, false, false, ) }) if err != nil { diff --git a/sonar-project.properties b/sonar-project.properties index 67da119cd2a..7ae3d52c3a5 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -44,8 +44,7 @@ sonar.coverage.exclusions=\ **/integration-tests/**/*,\ **/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 +**/0195_add_not_null_to_evm_chain_id_in_job_specs.go # Duplication exclusions: mercury excluded because current MercuryProvider and Factory APIs are inherently duplicated due to embedded versioning sonar.cpd.exclusions=\ From 035a22ed80af13270040726befbc498f9bd03724 Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Tue, 27 Feb 2024 16:16:54 +0100 Subject: [PATCH 06/20] ttl command to increase namespace time until removal (#12028) --- charts/chainlink-cluster/README.md | 7 +++++++ charts/chainlink-cluster/devspace.yaml | 2 ++ 2 files changed, 9 insertions(+) diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index 7f2736034a7..c06107d2669 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -31,6 +31,13 @@ Build and deploy current commit devspace deploy ``` +Default `ttl` is `72h`, use `ttl` command to update if you need more time + +Valid values are `1h`, `2m`, `3s`, etc. Go time format is invalid `1h2m3s` +``` +devspace run ttl ${namespace} 120h +``` + If you don't need a build use ``` devspace deploy --skip-build diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index f7808085505..95369e549cd 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -89,6 +89,8 @@ pipelines: commands: connect: |- sudo kubefwd svc -n $1 + ttl: |- + kubectl annotate namespace $1 janitor/ttl=$2 --overwrite images: app: From ddbf6b4ee5b9e06eb284491a0c1944a2f556b119 Mon Sep 17 00:00:00 2001 From: frank zhu Date: Tue, 27 Feb 2024 07:24:33 -0800 Subject: [PATCH 07/20] fix: grafana namespace and ingress for chainlink-cluster (#12180) * update devspace with tracing * add rbac namespace for grafana --- charts/chainlink-cluster/values.yaml | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index f922e6397ba..2bca739bfdf 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -272,6 +272,8 @@ grafana: enabled: true image: tag: 7.3.2 + rbac: + namespaced: true datasources: datasources.yaml: apiVersion: 1 @@ -402,6 +404,55 @@ affinity: networkPolicies: enabled: true + customPolicies: + grafanaToTempoEgress: + podSelector: + matchLabels: + app: grafana + egress: + - to: + - podSelector: + matchLabels: + app: tempo + ports: + - protocol: TCP + port: 3100 + tempoIngressFromGrafana: + podSelector: + matchLabels: + app: tempo + ingress: + - from: + - podSelector: + matchLabels: + app: grafana + ports: + - protocol: TCP + port: 3100 + chainlinkToOtelCollectorEgress: + podSelector: + matchLabels: + app: chainlink + egress: + - to: + - podSelector: + matchLabels: + app: otel-collector + ports: + - protocol: TCP + port: 4317 + otelCollectorToTempoEgress: + podSelector: + matchLabels: + app: otel-collector + egress: + - to: + - podSelector: + matchLabels: + app: tempo + ports: + - protocol: TCP + port: 3100 # Configure the default network policy. networkPolicyDefault: From 2ca09c2952ac19f36030ff7143d51b3b76e621b6 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:44:38 -0500 Subject: [PATCH 08/20] Pass in values correctly in devspace for network policy (#12187) --- charts/chainlink-cluster/devspace.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index 95369e549cd..338147675c5 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -302,12 +302,6 @@ deployments: # monitoring.coreos.com/v1 PodMonitor for each node prometheusMonitor: true - networkPolicy: - ingress: - # Should be a comma separated list of CIDR blocks. To include - # AWS ALB private CIDRs and optionally other custom CIDRs. - # Example format: 10.0.0.0/16,192.168.0.1/24 - allowCustomCidrs: ${DEVSPACE_INGRESS_CIDRS} # These ingresses create AWS ALB resources and Route 53 Records. ingress: enabled: true @@ -413,7 +407,13 @@ deployments: name: mockserver port: number: 1080 - + networkPolicyDefault: + ingress: + allowCustomCidrs: true + # Should be a comma separated list of CIDR blocks. To include + # AWS ALB private CIDRs and optionally other custom CIDRs. + # Example format: 10.0.0.0/16,192.168.0.1/24 + customCidrs: ${DEVSPACE_INGRESS_CIDRS} # deployment placement, standard helm stuff podAnnotations: nodeSelector: From 3666e4d77cbe4c82e24891287a592abf8451c260 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:58:19 -0500 Subject: [PATCH 09/20] Change chart ingress DNS record TTL from 5 mins to 2 mins (#12158) --- charts/chainlink-cluster/templates/ingress.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/chainlink-cluster/templates/ingress.yaml b/charts/chainlink-cluster/templates/ingress.yaml index e84de6eae69..9573ac54eb9 100644 --- a/charts/chainlink-cluster/templates/ingress.yaml +++ b/charts/chainlink-cluster/templates/ingress.yaml @@ -15,6 +15,7 @@ metadata: 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 + external-dns.alpha.kubernetes.io/ttl: "120" {{- if .Values.ingress.extra_annotations }} {{- range $key, $value := .Values.ingress.extra_annotations }} {{ $key }}: {{ $value | quote }} From 728a7abdad51b01c066b476d0324e582ba4bf73f Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Tue, 27 Feb 2024 16:11:58 +0000 Subject: [PATCH 10/20] Add 2.1+ version in job spec (#12184) * Add 2.1+ version in job spec and update changelog for old transmitter change * remove retro changelog * fix integration-tests for v2.2 (#12185) --------- Co-authored-by: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> --- core/services/ocr2/delegate.go | 3 +++ integration-tests/actions/automation_ocr_helpers.go | 7 +++---- integration-tests/actions/automation_ocr_helpers_local.go | 5 +++-- integration-tests/actions/automationv2/actions.go | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 8677f48e8b5..d41a143b616 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -1234,6 +1234,9 @@ func (d *Delegate) newServicesOCR2Keepers( switch cfg.ContractVersion { case "v2.1": return d.newServicesOCR2Keepers21(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) + case "v2.1+": + // Future contracts of v2.1 (v2.x) will use the same job spec as v2.1 + 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: diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index 9b564409c2a..3f8871d9d65 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -185,11 +185,10 @@ func CreateOCRKeeperJobs( bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID var contractVersion string - // TODO: use v2.1 for registry 2.2 for now until AUTO-9033 is done - if registryVersion == ethereum.RegistryVersion_2_1 || registryVersion == ethereum.RegistryVersion_2_2 { + if registryVersion == ethereum.RegistryVersion_2_2 { + contractVersion = "v2.1+" + } else if registryVersion == ethereum.RegistryVersion_2_1 { contractVersion = "v2.1" - } else if registryVersion == ethereum.RegistryVersion_2_0 { - contractVersion = "v2.0" } else { require.FailNow(t, "v2.0, v2.1, and v2.2 are the only supported versions") } diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go index 6c72956045a..1c563c5605a 100644 --- a/integration-tests/actions/automation_ocr_helpers_local.go +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -186,8 +186,9 @@ func CreateOCRKeeperJobsLocal( bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID var contractVersion string - // TODO: use v2.1 for registry 2.2 for now until AUTO-9033 is done - if registryVersion == ethereum.RegistryVersion_2_1 || registryVersion == ethereum.RegistryVersion_2_2 { + if registryVersion == ethereum.RegistryVersion_2_2 { + contractVersion = "v2.1+" + } else if registryVersion == ethereum.RegistryVersion_2_1 { contractVersion = "v2.1" } else if registryVersion == ethereum.RegistryVersion_2_0 { contractVersion = "v2.0" diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go index 5c181cc449b..a42fb297e6d 100644 --- a/integration-tests/actions/automationv2/actions.go +++ b/integration-tests/actions/automationv2/actions.go @@ -372,8 +372,9 @@ func (a *AutomationTest) AddBootstrapJob() error { func (a *AutomationTest) AddAutomationJobs() error { var contractVersion string - // TODO: use v2.1 for registry 2.2 for now until AUTO-9033 is done - if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_1 || a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_2 { + if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_2 { + contractVersion = "v2.1+" + } else if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_1 { contractVersion = "v2.1" } else if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_0 { contractVersion = "v2.0" From 23f767fd3c02b1c047f072c843d4d8cfbac7e271 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Tue, 27 Feb 2024 18:50:18 +0100 Subject: [PATCH 11/20] BCF-2854 Jfpc pipeline cache (#12094) * Add rough implementation for data source caching * Add JuelsPerFeeCoinCacheDuration validation * Make sonar happy * Set EATelemetry for dataSource in observe to reuse executeRun for cache * Fix races in inMemoryDataSourceCache * Fix JuelsPerFeeCoinCacheDuration validation * Shorten NewInMemoryDataSourceCache signature * Infer juels fee per coin caching from non-zero duration instead of bool * Change how jfpc cache handles cache updater cron errors * Change jfpc cache duration validation * Set default jfpc data source expiry duration to 5minutes if not set * Improve jfpc updateCache err handling to account for result errors * Make juels fee per coin get cached by default, and add cache tests * Make jfpc cache updater run on start * Increase jfpc data source timeout * Change log priority in cache updater * Fix test flakiness * Change log severity in jfpc cache updater * Add cfg option to disable jfpc caching * Remove ptr from inMemoryDataSourceCache mutex * Fix JuelsPerFeeCoinCacheDuration encoding type to use models.Interval * Add tests for validating juels per fee coin data source cache config * Add changelog * Fix typo in test * Fix log --- .../features/ocr2/features_ocr2_test.go | 2 + core/services/feeds/service_test.go | 3 + .../ocr2/plugins/median/config/config.go | 16 +- .../ocr2/plugins/median/config/config_test.go | 55 +++++-- core/services/ocr2/plugins/median/services.go | 14 +- core/services/ocrcommon/data_source.go | 138 +++++++++++++++--- core/services/ocrcommon/data_source_test.go | 49 +++++++ docs/CHANGELOG.md | 1 + 8 files changed, 242 insertions(+), 36 deletions(-) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index e089970951b..72d70720c65 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -487,6 +487,7 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ +juelsPerFeeCoinCacheDuration = "1m" `, 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) @@ -839,6 +840,7 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ +juelsPerFeeCoinCacheDuration = "1m" `, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index d822cd9787d..be3620efac5 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -124,6 +124,7 @@ ds1_multiply [type=multiply times=1.23]; ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ +juelsPerFeeCoinCacheDuration = "1m" ` const BootstrapTestSpecTemplate = ` type = "bootstrap" @@ -2186,6 +2187,7 @@ ds1_multiply [type=multiply times=1.23]; ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ +juelsPerFeeCoinCacheDuration = "30s" ` defn2 = ` name = 'LINK / ETH | version 3 | contract 0x0000000000000000000000000000000000000000' @@ -2215,6 +2217,7 @@ ds1_multiply [type=multiply times=1.23]; ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ +juelsPerFeeCoinCacheDuration = "20m" ` jp = &feeds.JobProposal{ diff --git a/core/services/ocr2/plugins/median/config/config.go b/core/services/ocr2/plugins/median/config/config.go index c86c75f7200..218f7491094 100644 --- a/core/services/ocr2/plugins/median/config/config.go +++ b/core/services/ocr2/plugins/median/config/config.go @@ -4,14 +4,19 @@ package config import ( + "time" + "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) // The PluginConfig struct contains the custom arguments needed for the Median plugin. type PluginConfig struct { - JuelsPerFeeCoinPipeline string `json:"juelsPerFeeCoinSource"` + JuelsPerFeeCoinPipeline string `json:"juelsPerFeeCoinSource"` + JuelsPerFeeCoinCacheDuration models.Interval `json:"juelsPerFeeCoinCacheDuration"` + JuelsPerFeeCoinCacheDisabled bool `json:"juelsPerFeeCoinCacheDisabled"` } // ValidatePluginConfig validates the arguments for the Median plugin. @@ -20,5 +25,14 @@ func ValidatePluginConfig(config PluginConfig) error { return errors.Wrap(err, "invalid juelsPerFeeCoinSource pipeline") } + // unset duration defaults later + if config.JuelsPerFeeCoinCacheDuration != 0 { + if config.JuelsPerFeeCoinCacheDuration.Duration() < time.Second*30 { + return errors.Errorf("juelsPerFeeCoinSource cache duration: %s is below 30 second minimum", config.JuelsPerFeeCoinCacheDuration.Duration().String()) + } else if config.JuelsPerFeeCoinCacheDuration.Duration() > time.Minute*20 { + return errors.Errorf("juelsPerFeeCoinSource cache duration: %s is above 20 minute maximum", config.JuelsPerFeeCoinCacheDuration.Duration().String()) + } + } + return nil } diff --git a/core/services/ocr2/plugins/median/config/config_test.go b/core/services/ocr2/plugins/median/config/config_test.go index 6e137992af5..e0dcd4f9203 100644 --- a/core/services/ocr2/plugins/median/config/config_test.go +++ b/core/services/ocr2/plugins/median/config/config_test.go @@ -1,22 +1,55 @@ package config import ( + "fmt" "testing" + "time" "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestValidatePluginConfig(t *testing.T) { - for _, s := range []struct { - name string - pipeline string - }{ - {"empty", ""}, - {"blank", " "}, - {"foo", "foo"}, - } { - t.Run(s.name, func(t *testing.T) { - assert.Error(t, ValidatePluginConfig(PluginConfig{JuelsPerFeeCoinPipeline: s.pipeline})) - }) + type testCase struct { + name string + pipeline string + cacheDuration models.Interval + expectedError error } + + t.Run("pipeline validation", func(t *testing.T) { + for _, tc := range []testCase{ + {"empty pipeline", "", models.Interval(time.Minute), fmt.Errorf("invalid juelsPerFeeCoinSource pipeline: empty pipeline")}, + {"blank pipeline", " ", models.Interval(time.Minute), fmt.Errorf("invalid juelsPerFeeCoinSource pipeline: empty pipeline")}, + {"foo pipeline", "foo", models.Interval(time.Minute), fmt.Errorf("invalid juelsPerFeeCoinSource pipeline: UnmarshalTaskFromMap: unknown task type: \"\"")}, + } { + t.Run(tc.name, func(t *testing.T) { + assert.EqualError(t, ValidatePluginConfig(PluginConfig{JuelsPerFeeCoinPipeline: tc.pipeline}), tc.expectedError.Error()) + }) + } + }) + + t.Run("cache duration validation", func(t *testing.T) { + for _, tc := range []testCase{ + {"cache duration below minimum", `ds1 [type=bridge name=voter_turnout];`, models.Interval(time.Second * 29), fmt.Errorf("juelsPerFeeCoinSource cache duration: 29s is below 30 second minimum")}, + {"cache duration above maximum", `ds1 [type=bridge name=voter_turnout];`, models.Interval(time.Minute*20 + time.Second), fmt.Errorf("juelsPerFeeCoinSource cache duration: 20m1s is above 20 minute maximum")}, + } { + t.Run(tc.name, func(t *testing.T) { + assert.EqualError(t, ValidatePluginConfig(PluginConfig{JuelsPerFeeCoinPipeline: tc.pipeline, JuelsPerFeeCoinCacheDuration: tc.cacheDuration}), tc.expectedError.Error()) + }) + } + }) + + t.Run("valid values", func(t *testing.T) { + for _, s := range []testCase{ + {"valid 0 cache duration and valid pipeline", `ds1 [type=bridge name=voter_turnout];`, 0, nil}, + {"valid duration and valid pipeline", `ds1 [type=bridge name=voter_turnout];`, models.Interval(time.Second * 30), nil}, + {"valid duration and valid pipeline", `ds1 [type=bridge name=voter_turnout];`, models.Interval(time.Minute * 20), nil}, + } { + t.Run(s.name, func(t *testing.T) { + assert.Nil(t, ValidatePluginConfig(PluginConfig{JuelsPerFeeCoinPipeline: s.pipeline})) + }) + } + }) } diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 2a874ff1756..74690565e94 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -113,18 +113,26 @@ func NewMedianServices(ctx context.Context, } } - dataSource, juelsPerFeeCoinSource := ocrcommon.NewDataSourceV2(pipelineRunner, + dataSource := ocrcommon.NewDataSourceV2(pipelineRunner, jb, *jb.PipelineSpec, lggr, runSaver, - chEnhancedTelem, - ), ocrcommon.NewInMemoryDataSource(pipelineRunner, jb, pipeline.Spec{ + chEnhancedTelem) + + juelsPerFeeCoinSource := ocrcommon.NewInMemoryDataSource(pipelineRunner, jb, pipeline.Spec{ ID: jb.ID, DotDagSource: pluginConfig.JuelsPerFeeCoinPipeline, CreatedAt: time.Now(), }, lggr) + if !pluginConfig.JuelsPerFeeCoinCacheDisabled { + lggr.Infof("juelsPerFeeCoin data source caching is enabled") + if juelsPerFeeCoinSource, err = ocrcommon.NewInMemoryDataSourceCache(juelsPerFeeCoinSource, pluginConfig.JuelsPerFeeCoinCacheDuration.Duration()); err != nil { + return nil, err + } + } + 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()) diff --git a/core/services/ocrcommon/data_source.go b/core/services/ocrcommon/data_source.go index 706376fbfd1..3dd7e4eebc0 100644 --- a/core/services/ocrcommon/data_source.go +++ b/core/services/ocrcommon/data_source.go @@ -2,6 +2,7 @@ package ocrcommon import ( "context" + errjoin "errors" "math/big" "sync" "time" @@ -98,8 +99,42 @@ func NewInMemoryDataSource(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, l } } +const defaultInMemoryCacheDuration = time.Minute * 5 + +func NewInMemoryDataSourceCache(ds median.DataSource, cacheExpiryDuration time.Duration) (median.DataSource, error) { + inMemoryDS, ok := ds.(*inMemoryDataSource) + if !ok { + return nil, errors.Errorf("unsupported data source type: %T, only inMemoryDataSource supported", ds) + } + + if cacheExpiryDuration == 0 { + cacheExpiryDuration = defaultInMemoryCacheDuration + } + + dsCache := &inMemoryDataSourceCache{ + cacheExpiration: cacheExpiryDuration, + inMemoryDataSource: inMemoryDS, + } + go func() { dsCache.updater() }() + return dsCache, nil +} + var _ ocr1types.DataSource = (*dataSource)(nil) +func setEATelemetry(ds *inMemoryDataSource, finalResult pipeline.FinalResult, trrs pipeline.TaskRunResults, timestamp ObservationTimestamp) { + promSetFinalResultMetrics(ds, &finalResult) + promSetBridgeParseMetrics(ds, &trrs) + if ShouldCollectEnhancedTelemetry(&ds.jb) { + EnqueueEnhancedTelem(ds.chEnhancedTelemetry, EnhancedTelemetryData{ + TaskRunResults: trrs, + FinalResults: finalResult, + RepTimestamp: timestamp, + }) + } else { + ds.lggr.Infow("Enhanced telemetry is disabled for job", "job", ds.jb.Name) + } +} + func (ds *inMemoryDataSource) updateAnswer(a *big.Int) { ds.mu.Lock() defer ds.mu.Unlock() @@ -117,7 +152,7 @@ func (ds *inMemoryDataSource) currentAnswer() (*big.Int, *big.Int) { // 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 (ds *inMemoryDataSource) executeRun(ctx context.Context, timestamp ObservationTimestamp) (*pipeline.Run, pipeline.FinalResult, error) { +func (ds *inMemoryDataSource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { md, err := bridges.MarshalBridgeMetaData(ds.currentAnswer()) if err != nil { ds.lggr.Warnw("unable to attach metadata for run", "err", err) @@ -136,23 +171,10 @@ func (ds *inMemoryDataSource) executeRun(ctx context.Context, timestamp Observat run, trrs, err := ds.pipelineRunner.ExecuteRun(ctx, ds.spec, vars, ds.lggr) if err != nil { - return nil, pipeline.FinalResult{}, errors.Wrapf(err, "error executing run for spec ID %v", ds.spec.ID) - } - finalResult := trrs.FinalResult(ds.lggr) - promSetBridgeParseMetrics(ds, &trrs) - promSetFinalResultMetrics(ds, &finalResult) - - if ShouldCollectEnhancedTelemetry(&ds.jb) { - EnqueueEnhancedTelem(ds.chEnhancedTelemetry, EnhancedTelemetryData{ - TaskRunResults: trrs, - FinalResults: finalResult, - RepTimestamp: timestamp, - }) - } else { - ds.lggr.Infow("Enhanced telemetry is disabled for job", "job", ds.jb.Name) + return nil, pipeline.TaskRunResults{}, errors.Wrapf(err, "error executing run for spec ID %v", ds.spec.ID) } - return run, finalResult, err + return run, trrs, err } // parse uses the FinalResult into a big.Int and stores it in the bridge metadata @@ -176,19 +198,90 @@ func (ds *inMemoryDataSource) parse(finalResult pipeline.FinalResult) (*big.Int, // Observe without saving to DB func (ds *inMemoryDataSource) Observe(ctx context.Context, timestamp ocr2types.ReportTimestamp) (*big.Int, error) { - _, finalResult, err := ds.executeRun(ctx, ObservationTimestamp{ + _, trrs, err := ds.executeRun(ctx) + if err != nil { + return nil, err + } + + finalResult := trrs.FinalResult(ds.lggr) + setEATelemetry(ds, finalResult, trrs, ObservationTimestamp{ Round: timestamp.Round, Epoch: timestamp.Epoch, ConfigDigest: timestamp.ConfigDigest.Hex(), }) - if err != nil { - return nil, err - } + return ds.parse(finalResult) } +// inMemoryDataSourceCache is a time based cache wrapper for inMemoryDataSource. +// If cache update is overdue Observe defaults to standard inMemoryDataSource behaviour. +type inMemoryDataSourceCache struct { + *inMemoryDataSource + cacheExpiration time.Duration + mu sync.RWMutex + latestUpdateErr error + latestTrrs pipeline.TaskRunResults + latestResult pipeline.FinalResult +} + +// updater periodically updates data source cache. +func (ds *inMemoryDataSourceCache) updater() { + ticker := time.NewTicker(ds.cacheExpiration) + for ; true; <-ticker.C { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + if err := ds.updateCache(ctx); err != nil { + ds.lggr.Infow("failed to update cache", "err", err) + } + cancel() + } +} + +func (ds *inMemoryDataSourceCache) updateCache(ctx context.Context) error { + ds.mu.Lock() + defer ds.mu.Unlock() + _, ds.latestTrrs, ds.latestUpdateErr = ds.executeRun(ctx) + if ds.latestUpdateErr != nil { + return errors.Wrapf(ds.latestUpdateErr, "error executing run for spec ID %v", ds.spec.ID) + } else if ds.latestTrrs.FinalResult(ds.lggr).HasErrors() { + ds.latestUpdateErr = errjoin.Join(ds.latestTrrs.FinalResult(ds.lggr).AllErrors...) + return errors.Wrapf(ds.latestUpdateErr, "error executing run for spec ID %v", ds.spec.ID) + } + + ds.latestResult = ds.latestTrrs.FinalResult(ds.lggr) + return nil +} + +func (ds *inMemoryDataSourceCache) get(ctx context.Context) (pipeline.FinalResult, pipeline.TaskRunResults) { + ds.mu.RLock() + // updater didn't error, so we know that the latestResult is fresh + if ds.latestUpdateErr == nil { + defer ds.mu.RUnlock() + return ds.latestResult, ds.latestTrrs + } + ds.mu.RUnlock() + + if err := ds.updateCache(ctx); err != nil { + ds.lggr.Errorw("failed to update cache, returning stale result now", "err", err) + } + + ds.mu.RLock() + defer ds.mu.RUnlock() + return ds.latestResult, ds.latestTrrs +} + +func (ds *inMemoryDataSourceCache) Observe(ctx context.Context, timestamp ocr2types.ReportTimestamp) (*big.Int, error) { + latestResult, latestTrrs := ds.get(ctx) + setEATelemetry(ds.inMemoryDataSource, latestResult, latestTrrs, ObservationTimestamp{ + Round: timestamp.Round, + Epoch: timestamp.Epoch, + ConfigDigest: timestamp.ConfigDigest.Hex(), + }) + + return ds.parse(latestResult) +} + func (ds *dataSourceBase) observe(ctx context.Context, timestamp ObservationTimestamp) (*big.Int, error) { - run, finalResult, err := ds.inMemoryDataSource.executeRun(ctx, timestamp) + run, trrs, err := ds.inMemoryDataSource.executeRun(ctx) if err != nil { return nil, err } @@ -201,6 +294,9 @@ func (ds *dataSourceBase) observe(ctx context.Context, timestamp ObservationTime // a db write block that. ds.saver.Save(run) + finalResult := trrs.FinalResult(ds.lggr) + setEATelemetry(&ds.inMemoryDataSource, finalResult, trrs, timestamp) + return ds.inMemoryDataSource.parse(finalResult) } diff --git a/core/services/ocrcommon/data_source_test.go b/core/services/ocrcommon/data_source_test.go index 3ffc6b31e8c..2e4e07973a0 100644 --- a/core/services/ocrcommon/data_source_test.go +++ b/core/services/ocrcommon/data_source_test.go @@ -1,8 +1,10 @@ package ocrcommon_test import ( + "fmt" "math/big" "testing" + "time" promtestutil "github.com/prometheus/client_golang/prometheus/testutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -44,6 +46,53 @@ func Test_InMemoryDataSource(t *testing.T) { assert.Equal(t, mockValue, val.String()) // returns expected value after pipeline run } +func Test_CachedInMemoryDataSourceErrHandling(t *testing.T) { + runner := pipelinemocks.NewRunner(t) + + ds := ocrcommon.NewInMemoryDataSource(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t)) + dsCache, err := ocrcommon.NewInMemoryDataSourceCache(ds, time.Second*2) + require.NoError(t, err) + + changeResultValue := func(value string, returnErr, once bool) { + result := pipeline.Result{ + Value: value, + Error: nil, + } + if returnErr { + result.Error = assert.AnError + } + + call := runner.On("ExecuteRun", mock.Anything, mock.AnythingOfType("pipeline.Spec"), mock.Anything, mock.Anything). + Return(&pipeline.Run{}, pipeline.TaskRunResults{ + { + Result: result, + Task: &pipeline.HTTPTask{}, + }, + }, nil) + // last mock can't be Once or test will panic because there are logs after it finished + if once { + call.Once() + } + } + + mockVal := int64(1) + // Test if Observe notices that cache updater failed and can refresh the cache on its own + // 1. Set initial value + changeResultValue(fmt.Sprint(mockVal), false, true) + time.Sleep(time.Millisecond * 100) + val, err := dsCache.Observe(testutils.Context(t), types.ReportTimestamp{}) + require.NoError(t, err) + assert.Equal(t, mockVal, val.Int64()) + // 2. Set values again, but make it error in updater + changeResultValue(fmt.Sprint(mockVal+1), true, true) + time.Sleep(time.Second*2 + time.Millisecond*100) + // 3. Set value in between updates and call Observe (shouldn't flake because of huge wait time) + changeResultValue(fmt.Sprint(mockVal+2), false, false) + val, err = dsCache.Observe(testutils.Context(t), types.ReportTimestamp{}) + require.NoError(t, err) + assert.Equal(t, mockVal+2, val.Int64()) +} + func Test_InMemoryDataSourceWithProm(t *testing.T) { runner := pipelinemocks.NewRunner(t) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b7c37ecb348..0d1a5cc365e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Gas bumping logic to the `SuggestedPriceEstimator`. The bumping mechanism for this estimator refetches the price from the RPC and adds a buffer on top using the greater of `BumpPercent` and `BumpMin`. - Add preliminary support for "llo" job type (Data Streams V1) - Add `LogPrunePageSize` parameter to the EVM configuration. This parameter controls the number of logs removed during prune phase in LogPoller. Default value is 0, which deletes all logs at once - exactly how it used to work, so it doesn't require any changes on the product's side. +- Add Juels Fee Per Coin data source caching for OCR2 Feeds. Cache is time based and is turned on by default with default cache refresh of 5 minutes. Cache can be configured through pluginconfig using "juelsPerFeeCoinCacheDuration" and "juelsPerFeeCoinCacheDisabled" tags. Duration tag accepts values between "30s" and "20m" with default of "0s" that is overridden on cache startup to 5 minutes. ### Fixed From d50c3790f71d7d57bc5a4a151c7eb59119916ca5 Mon Sep 17 00:00:00 2001 From: frank zhu Date: Tue, 27 Feb 2024 10:56:15 -0800 Subject: [PATCH 12/20] chore: update otel-collector version (#12191) * update open-telemetry chart version * update otel-collector version to 0.95.0 * otel-telemetry 0.82.0 chart version --- charts/chainlink-cluster/Chart.lock | 6 +++--- charts/chainlink-cluster/Chart.yaml | 4 ++-- charts/chainlink-cluster/values.yaml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/chainlink-cluster/Chart.lock b/charts/chainlink-cluster/Chart.lock index ec87bb6d24e..38e7f09705e 100644 --- a/charts/chainlink-cluster/Chart.lock +++ b/charts/chainlink-cluster/Chart.lock @@ -4,12 +4,12 @@ dependencies: version: 5.14.0 - name: opentelemetry-collector repository: https://open-telemetry.github.io/opentelemetry-helm-charts - version: 0.81.2 + version: 0.82.0 - name: tempo repository: https://grafana.github.io/helm-charts version: 1.7.2 - name: grafana repository: https://grafana.github.io/helm-charts version: 7.3.2 -digest: sha256:fb13a8a7b490fd1e388a6b082e50d65a39f44a28030d66559d4640c687a70e20 -generated: "2024-02-23T15:22:09.284013-06:00" +digest: sha256:37722063f68689c42ac1d6549ddfae4756370c1659b8ac1c0d7da8916c6fad3d +generated: "2024-02-27T11:04:29.920915-06:00" diff --git a/charts/chainlink-cluster/Chart.yaml b/charts/chainlink-cluster/Chart.yaml index dc6f390f8a8..fa45ea9bd77 100644 --- a/charts/chainlink-cluster/Chart.yaml +++ b/charts/chainlink-cluster/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: chainlink-cluster description: Chainlink nodes cluster -version: 0.3.0 +version: 0.4.0 appVersion: "2.6.0" dependencies: - name: mockserver @@ -9,7 +9,7 @@ dependencies: repository: "https://www.mock-server.com" condition: mockserver.enabled - name: opentelemetry-collector - version: "0.81.2" + version: "0.82.0" repository: "https://open-telemetry.github.io/opentelemetry-helm-charts" condition: opentelemetry-collector.enabled - name: tempo diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index 2bca739bfdf..303cec04213 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -197,7 +197,7 @@ opentelemetry-collector: mode: deployment image: repository: otel/opentelemetry-collector - tag: 0.81.2 + tag: 0.95.0 command: name: otelcol extraVolumes: From 2d9342e452bf4f57a82d0b33b9dce48a5ec8e1d8 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 27 Feb 2024 19:23:32 +0000 Subject: [PATCH 13/20] [KS-59] Start capability service (#12171) - Start capability service - Bump golangci-lint version - Add fatal logging to OCR3 capability start --- GNUmakefile | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- plugins/cmd/chainlink-ocr3-capability/main.go | 12 +++++++++++- 10 files changed, 24 insertions(+), 14 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 8cbd0953ee7..c68e13f8ae6 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -145,7 +145,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.55.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.56.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 91697eb5f9f..5039897bec8 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -20,7 +20,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e 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-20240215150045-fe2ba71b2f0a diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7a3f6b2f0c2..066bc9592a5 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1173,8 +1173,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240221153538-1ea85cf3dc6c h1:ielGD+tVCB+irZ+nDt5VDTYJauJI88tirkLLaHWLaTs= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/go.mod b/go.mod index 1e0c09b06bf..6dab12267db 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 diff --git a/go.sum b/go.sum index 13d684fd34d..e04289334ee 100644 --- a/go.sum +++ b/go.sum @@ -1168,8 +1168,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240221153538-1ea85cf3dc6c h1:ielGD+tVCB+irZ+nDt5VDTYJauJI88tirkLLaHWLaTs= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index cf3f065d812..caec4f79373 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e github.com/smartcontractkit/chainlink-testing-framework v1.24.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 05717c79210..0340d6b31ac 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1507,8 +1507,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240221153538-1ea85cf3dc6c h1:ielGD+tVCB+irZ+nDt5VDTYJauJI88tirkLLaHWLaTs= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 016d8c5c91a..ab78012d982 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -15,7 +15,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e github.com/smartcontractkit/chainlink-testing-framework v1.24.1 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 803c56b8d71..a6517124c67 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1490,8 +1490,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240221153538-1ea85cf3dc6c h1:ielGD+tVCB+irZ+nDt5VDTYJauJI88tirkLLaHWLaTs= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240221153538-1ea85cf3dc6c/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/plugins/cmd/chainlink-ocr3-capability/main.go b/plugins/cmd/chainlink-ocr3-capability/main.go index ac8bb6454f3..85767554a1c 100644 --- a/plugins/cmd/chainlink-ocr3-capability/main.go +++ b/plugins/cmd/chainlink-ocr3-capability/main.go @@ -1,6 +1,8 @@ package main import ( + "context" + "github.com/hashicorp/go-plugin" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3" @@ -19,7 +21,15 @@ func main() { s := loop.MustNewStartedServer(loggerName) defer s.Stop() - p := ocr3.NewOCR3(s.Logger, evm.NewEVMEncoder) + c := ocr3.Config{ + Logger: s.Logger, + EncoderFactory: evm.NewEVMEncoder, + } + p := ocr3.NewOCR3(c) + if err := p.Start(context.Background()); err != nil { + s.Logger.Fatal("Failed to start OCR3 capability", err) + } + defer s.Logger.ErrorIfFn(p.Close, "Failed to close") s.MustRegister(p) From 17287df41385b684e1521eafdae3987d6178939c Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Tue, 27 Feb 2024 21:25:42 +0100 Subject: [PATCH 14/20] BCI-2450: Health check for MultiNode to ensure that node is not in syncing state (#11765) * syncing state for multinode * fix evm tests * zombie check for syncing node * Update common/client/node_fsm.go Co-authored-by: Sam * make IsSyncing check optional * regen config docs * remove merge artefact * add description to the test * fix config docs * fix RPC client mock generation * regen mocks --------- Co-authored-by: Sam --- common/client/mock_node_client_test.go | 28 ++ common/client/mock_rpc_test.go | 28 ++ common/client/node.go | 67 ++- common/client/node_fsm.go | 63 ++- common/client/node_fsm_test.go | 44 +- common/client/node_lifecycle.go | 110 +++-- common/client/node_lifecycle_test.go | 417 +++++++++++++++++- common/client/node_test.go | 6 + common/client/types.go | 2 + core/chains/evm/client/chain_client.go | 8 +- core/chains/evm/client/chain_client_test.go | 4 +- core/chains/evm/client/helpers_test.go | 20 +- core/chains/evm/client/mocks/rpc_client.go | 118 +++-- core/chains/evm/client/rpc_client.go | 35 +- .../evm/config/chain_scoped_node_pool.go | 4 + core/chains/evm/config/config.go | 1 + core/chains/evm/config/config_test.go | 2 + core/chains/evm/config/toml/config.go | 4 + .../evm/config/toml/defaults/fallback.toml | 1 + core/chains/legacyevm/chain.go | 8 +- core/config/docs/chains-evm.toml | 6 + core/internal/testutils/testutils.go | 2 + core/services/chainlink/config_test.go | 2 + .../chainlink/testdata/config-full.toml | 1 + .../config-multi-chain-effective.toml | 3 + core/web/resolver/testdata/config-full.toml | 1 + .../config-multi-chain-effective.toml | 3 + docs/CHANGELOG.md | 1 + docs/CONFIG.md | 62 +++ .../disk-based-logging-disabled.txtar | 1 + .../validate/disk-based-logging-no-dir.txtar | 1 + .../node/validate/disk-based-logging.txtar | 1 + testdata/scripts/node/validate/invalid.txtar | 1 + testdata/scripts/node/validate/valid.txtar | 1 + 34 files changed, 908 insertions(+), 148 deletions(-) diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index 661ad68ede5..d143ebb88a5 100644 --- a/common/client/mock_node_client_test.go +++ b/common/client/mock_node_client_test.go @@ -116,6 +116,34 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) DisconnectAll() { _m.Called() } +// IsSyncing provides a mock function with given fields: ctx +func (_m *mockNodeClient[CHAIN_ID, HEAD]) IsSyncing(ctx context.Context) (bool, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for IsSyncing") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SetAliveLoopSub provides a mock function with given fields: _a0 func (_m *mockNodeClient[CHAIN_ID, HEAD]) SetAliveLoopSub(_a0 types.Subscription) { _m.Called(_a0) diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index 465445b8092..60e0cb4b421 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -366,6 +366,34 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS return r0, r1 } +// IsSyncing provides a mock function with given fields: ctx +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) IsSyncing(ctx context.Context) (bool, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for IsSyncing") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // LINKBalance provides a mock function with given fields: ctx, accountAddress, linkAddress func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) LINKBalance(ctx context.Context, accountAddress ADDR, linkAddress ADDR) (*assets.Link, error) { ret := _m.Called(ctx, accountAddress, linkAddress) diff --git a/common/client/node.go b/common/client/node.go index ce144bbca86..ee9ff5eb1c0 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -42,6 +42,7 @@ type NodeConfig interface { PollInterval() time.Duration SelectionMode() string SyncThreshold() uint32 + NodeIsSyncingEnabled() bool } //go:generate mockery --quiet --name Node --structname mockNode --filename "mock_node_test.go" --inpackage --case=underscore @@ -224,23 +225,14 @@ func (n *node[CHAIN_ID, HEAD, RPC]) start(startCtx context.Context) { } n.setState(nodeStateDialed) - if err := n.verify(startCtx); errors.Is(err, errInvalidChainID) { - n.lfcLog.Errorw("Verify failed: Node has the wrong chain ID", "err", err) - n.declareInvalidChainID() - return - } else if err != nil { - n.lfcLog.Errorw(fmt.Sprintf("Verify failed: %v", err), "err", err) - n.declareUnreachable() - return - } - - n.declareAlive() + state := n.verifyConn(startCtx, n.lfcLog) + n.declareState(state) } -// verify checks that all connections to eth nodes match the given chain ID +// verifyChainID checks that connection to the node matches the given chain ID // Not thread-safe -// Pure verify: does not mutate node "state" field. -func (n *node[CHAIN_ID, HEAD, RPC]) verify(callerCtx context.Context) (err error) { +// Pure verifyChainID: does not mutate node "state" field. +func (n *node[CHAIN_ID, HEAD, RPC]) verifyChainID(callerCtx context.Context, lggr logger.Logger) nodeState { promPoolRPCNodeVerifies.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() promFailed := func() { promPoolRPCNodeVerifiesFailed.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() @@ -248,29 +240,68 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verify(callerCtx context.Context) (err error st := n.State() switch st { - case nodeStateDialed, nodeStateOutOfSync, nodeStateInvalidChainID: + case nodeStateDialed, nodeStateOutOfSync, nodeStateInvalidChainID, nodeStateSyncing: default: panic(fmt.Sprintf("cannot verify node in state %v", st)) } var chainID CHAIN_ID + var err error if chainID, err = n.rpc.ChainID(callerCtx); err != nil { promFailed() - return fmt.Errorf("failed to verify chain ID for node %s: %w", n.name, err) + lggr.Errorw("Failed to verify chain ID for node", "err", err, "nodeState", n.State()) + return nodeStateUnreachable } else if chainID.String() != n.chainID.String() { promFailed() - return fmt.Errorf( + err = 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, ) + lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err, "nodeState", n.State()) + return nodeStateInvalidChainID } promPoolRPCNodeVerifiesSuccess.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() - return nil + return nodeStateAlive +} + +// createVerifiedConn - establishes new connection with the RPC and verifies that it's valid: chainID matches, and it's not syncing. +// Returns desired state if one of the verifications fails. Otherwise, returns nodeStateAlive. +func (n *node[CHAIN_ID, HEAD, RPC]) createVerifiedConn(ctx context.Context, lggr logger.Logger) nodeState { + if err := n.rpc.Dial(ctx); err != nil { + n.lfcLog.Errorw("Dial failed: Node is unreachable", "err", err, "nodeState", n.State()) + return nodeStateUnreachable + } + + return n.verifyConn(ctx, lggr) +} + +// verifyConn - verifies that current connection is valid: chainID matches, and it's not syncing. +// Returns desired state if one of the verifications fails. Otherwise, returns nodeStateAlive. +func (n *node[CHAIN_ID, HEAD, RPC]) verifyConn(ctx context.Context, lggr logger.Logger) nodeState { + state := n.verifyChainID(ctx, lggr) + if state != nodeStateAlive { + return state + } + + if n.nodePoolCfg.NodeIsSyncingEnabled() { + isSyncing, err := n.rpc.IsSyncing(ctx) + if err != nil { + lggr.Errorw("Unexpected error while verifying RPC node synchronization status", "err", err, "nodeState", n.State()) + return nodeStateUnreachable + } + + if isSyncing { + lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.State()) + return nodeStateSyncing + } + } + + return nodeStateAlive } // disconnectAll disconnects all clients connected to the node diff --git a/common/client/node_fsm.go b/common/client/node_fsm.go index 74a5814f773..4cb020893b5 100644 --- a/common/client/node_fsm.go +++ b/common/client/node_fsm.go @@ -33,6 +33,10 @@ var ( Name: "pool_rpc_node_num_transitions_to_unusable", Help: transitionString(nodeStateUnusable), }, []string{"chainID", "nodeName"}) + promPoolRPCNodeTransitionsToSyncing = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "pool_rpc_node_num_transitions_to_syncing", + Help: transitionString(nodeStateSyncing), + }, []string{"chainID", "nodeName"}) ) // nodeState represents the current state of the node @@ -57,6 +61,8 @@ func (n nodeState) String() string { return "OutOfSync" case nodeStateClosed: return "Closed" + case nodeStateSyncing: + return "Syncing" default: return fmt.Sprintf("nodeState(%d)", n) } @@ -87,6 +93,11 @@ const ( nodeStateUnusable // nodeStateClosed is after the connection has been closed and the node is at the end of its lifecycle nodeStateClosed + // nodeStateSyncing is a node that is actively back-filling blockchain. Usually, it's a newly set up node that is + // still syncing the chain. The main difference from `nodeStateOutOfSync` is that it represents state relative + // to other primary nodes configured in the MultiNode. In contrast, `nodeStateSyncing` represents the internal state of + // the node (RPC). + nodeStateSyncing // nodeStateLen tracks the number of states nodeStateLen ) @@ -144,7 +155,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToAlive(fn func()) { return } switch n.state { - case nodeStateDialed, nodeStateInvalidChainID: + case nodeStateDialed, nodeStateInvalidChainID, nodeStateSyncing: n.state = nodeStateAlive default: panic(transitionFail(n.state, nodeStateAlive)) @@ -171,7 +182,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInSync(fn func()) { return } switch n.state { - case nodeStateOutOfSync: + case nodeStateOutOfSync, nodeStateSyncing: n.state = nodeStateAlive default: panic(transitionFail(n.state, nodeStateAlive)) @@ -222,7 +233,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToUnreachable(fn func()) { return } switch n.state { - case nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID: + case nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID, nodeStateSyncing: n.disconnectAll() n.state = nodeStateUnreachable default: @@ -231,6 +242,21 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToUnreachable(fn func()) { fn() } +func (n *node[CHAIN_ID, HEAD, RPC]) declareState(state nodeState) { + switch state { + case nodeStateInvalidChainID: + n.declareInvalidChainID() + case nodeStateUnreachable: + n.declareUnreachable() + case nodeStateSyncing: + n.declareSyncing() + case nodeStateAlive: + n.declareAlive() + default: + panic(fmt.Sprintf("%#v state declaration is not implemented", state)) + } +} + func (n *node[CHAIN_ID, HEAD, RPC]) declareInvalidChainID() { n.transitionToInvalidChainID(func() { n.lfcLog.Errorw("RPC Node has the wrong chain ID", "nodeState", n.state) @@ -247,7 +273,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInvalidChainID(fn func()) { return } switch n.state { - case nodeStateDialed, nodeStateOutOfSync: + case nodeStateDialed, nodeStateOutOfSync, nodeStateSyncing: n.disconnectAll() n.state = nodeStateInvalidChainID default: @@ -256,6 +282,35 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInvalidChainID(fn func()) { fn() } +func (n *node[CHAIN_ID, HEAD, RPC]) declareSyncing() { + n.transitionToSyncing(func() { + n.lfcLog.Errorw("RPC Node is syncing", "nodeState", n.state) + n.wg.Add(1) + go n.syncingLoop() + }) +} + +func (n *node[CHAIN_ID, HEAD, RPC]) transitionToSyncing(fn func()) { + promPoolRPCNodeTransitionsToSyncing.WithLabelValues(n.chainID.String(), n.name).Inc() + n.stateMu.Lock() + defer n.stateMu.Unlock() + if n.state == nodeStateClosed { + return + } + switch n.state { + case nodeStateDialed, nodeStateOutOfSync, nodeStateInvalidChainID: + n.disconnectAll() + n.state = nodeStateSyncing + default: + panic(transitionFail(n.state, nodeStateSyncing)) + } + + if !n.nodePoolCfg.NodeIsSyncingEnabled() { + panic("unexpected transition to nodeStateSyncing, while it's disabled") + } + fn() +} + func transitionString(state nodeState) string { return fmt.Sprintf("Total number of times node has transitioned to %s", state) } diff --git a/common/client/node_fsm_test.go b/common/client/node_fsm_test.go index 87e90846699..36cee65e09e 100644 --- a/common/client/node_fsm_test.go +++ b/common/client/node_fsm_test.go @@ -2,6 +2,7 @@ package client import ( "slices" + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -23,15 +24,11 @@ func (fm *fnMock) AssertCalled(t *testing.T) { assert.Greater(t, fm.calls, 0) } -func newTestTransitionNode(t *testing.T, rpc *mockNodeClient[types.ID, Head]) testNode { - return newTestNode(t, testNodeOpts{rpc: rpc}) -} - func TestUnit_Node_StateTransitions(t *testing.T) { t.Parallel() t.Run("setState", func(t *testing.T) { - n := newTestTransitionNode(t, nil) + n := newTestNode(t, testNodeOpts{rpc: nil, config: testNodeConfig{nodeIsSyncingEnabled: true}}) assert.Equal(t, nodeStateUndialed, n.State()) n.setState(nodeStateAlive) assert.Equal(t, nodeStateAlive, n.State()) @@ -41,14 +38,14 @@ func TestUnit_Node_StateTransitions(t *testing.T) { t.Run("transitionToAlive", func(t *testing.T) { const destinationState = nodeStateAlive - allowedStates := []nodeState{nodeStateDialed, nodeStateInvalidChainID} + allowedStates := []nodeState{nodeStateDialed, nodeStateInvalidChainID, nodeStateSyncing} rpc := newMockNodeClient[types.ID, Head](t) testTransition(t, rpc, testNode.transitionToAlive, destinationState, allowedStates...) }) t.Run("transitionToInSync", func(t *testing.T) { const destinationState = nodeStateAlive - allowedStates := []nodeState{nodeStateOutOfSync} + allowedStates := []nodeState{nodeStateOutOfSync, nodeStateSyncing} rpc := newMockNodeClient[types.ID, Head](t) testTransition(t, rpc, testNode.transitionToInSync, destinationState, allowedStates...) }) @@ -61,22 +58,40 @@ func TestUnit_Node_StateTransitions(t *testing.T) { }) t.Run("transitionToUnreachable", func(t *testing.T) { const destinationState = nodeStateUnreachable - allowedStates := []nodeState{nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID} + allowedStates := []nodeState{nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID, nodeStateSyncing} rpc := newMockNodeClient[types.ID, Head](t) rpc.On("DisconnectAll").Times(len(allowedStates)) testTransition(t, rpc, testNode.transitionToUnreachable, destinationState, allowedStates...) }) t.Run("transitionToInvalidChain", func(t *testing.T) { const destinationState = nodeStateInvalidChainID - allowedStates := []nodeState{nodeStateDialed, nodeStateOutOfSync} + allowedStates := []nodeState{nodeStateDialed, nodeStateOutOfSync, nodeStateSyncing} rpc := newMockNodeClient[types.ID, Head](t) rpc.On("DisconnectAll").Times(len(allowedStates)) testTransition(t, rpc, testNode.transitionToInvalidChainID, destinationState, allowedStates...) }) + t.Run("transitionToSyncing", func(t *testing.T) { + const destinationState = nodeStateSyncing + allowedStates := []nodeState{nodeStateDialed, nodeStateOutOfSync, nodeStateInvalidChainID} + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("DisconnectAll").Times(len(allowedStates)) + testTransition(t, rpc, testNode.transitionToSyncing, destinationState, allowedStates...) + }) + t.Run("transitionToSyncing panics if nodeIsSyncing is disabled", func(t *testing.T) { + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("DisconnectAll").Once() + node := newTestNode(t, testNodeOpts{rpc: rpc}) + node.setState(nodeStateDialed) + fn := new(fnMock) + defer fn.AssertNotCalled(t) + assert.PanicsWithValue(t, "unexpected transition to nodeStateSyncing, while it's disabled", func() { + node.transitionToSyncing(fn.Fn) + }) + }) } func testTransition(t *testing.T, rpc *mockNodeClient[types.ID, Head], transition func(node testNode, fn func()), destinationState nodeState, allowedStates ...nodeState) { - node := newTestTransitionNode(t, rpc) + node := newTestNode(t, testNodeOpts{rpc: rpc, config: testNodeConfig{nodeIsSyncingEnabled: true}}) for _, allowedState := range allowedStates { m := new(fnMock) node.setState(allowedState) @@ -106,3 +121,12 @@ func testTransition(t *testing.T, rpc *mockNodeClient[types.ID, Head], transitio } } + +func TestNodeState_String(t *testing.T) { + t.Run("Ensure all states are meaningful when converted to string", func(t *testing.T) { + for _, ns := range allNodeStates { + // ensure that string representation is not nodeState(%d) + assert.NotContains(t, ns.String(), strconv.FormatInt(int64(ns), 10), "Expected node state to have readable name") + } + }) +} diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index af8f27d498d..20902277480 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -2,7 +2,6 @@ package client import ( "context" - "errors" "fmt" "math" "math/big" @@ -282,16 +281,9 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected - if err := n.rpc.Dial(n.nodeCtx); err != nil { - lggr.Errorw("Failed to dial out-of-sync RPC node", "nodeState", n.State()) - n.declareUnreachable() - return - } - - // Manually re-verify since out-of-sync nodes are automatically disconnected - if err := n.verify(n.nodeCtx); err != nil { - lggr.Errorw(fmt.Sprintf("Failed to verify out-of-sync RPC node: %v", err), "err", err) - n.declareInvalidChainID() + state := n.createVerifiedConn(n.nodeCtx, lggr) + if state != nodeStateAlive { + n.declareState(state) return } @@ -377,21 +369,18 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { n.setState(nodeStateDialed) - err = n.verify(n.nodeCtx) - - if errors.Is(err, errInvalidChainID) { - lggr.Errorw("Failed to redial RPC node; remote endpoint returned the wrong chain ID", "err", err) - n.declareInvalidChainID() - return - } else if err != nil { - lggr.Errorw(fmt.Sprintf("Failed to redial RPC node; verify failed: %v", err), "err", err) - n.declareUnreachable() + state := n.verifyConn(n.nodeCtx, lggr) + switch state { + case nodeStateUnreachable: + n.setState(nodeStateUnreachable) + continue + case nodeStateAlive: + lggr.Infow(fmt.Sprintf("Successfully redialled and verified RPC node %s. Node was offline for %s", n.String(), time.Since(unreachableAt)), "nodeState", n.State()) + fallthrough + default: + n.declareState(state) return } - - lggr.Infow(fmt.Sprintf("Successfully redialled and verified RPC node %s. Node was offline for %s", n.String(), time.Since(unreachableAt)), "nodeState", n.State()) - n.declareAlive() - return } } } @@ -414,6 +403,14 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { invalidAt := time.Now() lggr := logger.Named(n.lfcLog, "InvalidChainID") + + // Need to redial since invalid chain ID nodes are automatically disconnected + state := n.createVerifiedConn(n.nodeCtx, lggr) + if state != nodeStateInvalidChainID { + n.declareState(state) + return + } + lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) chainIDRecheckBackoff := iutils.NewRedialBackoff() @@ -423,18 +420,71 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { case <-n.nodeCtx.Done(): return case <-time.After(chainIDRecheckBackoff.Duration()): - err := n.verify(n.nodeCtx) - if errors.Is(err, errInvalidChainID) { - lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err) + state := n.verifyConn(n.nodeCtx, lggr) + switch state { + case nodeStateInvalidChainID: continue - } else if err != nil { - lggr.Errorw(fmt.Sprintf("Unexpected error while verifying RPC node chain ID; %v", err), "err", err) + case nodeStateAlive: + lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was offline for %s", time.Since(invalidAt)), "nodeState", n.State()) + fallthrough + default: + n.declareState(state) + return + } + } + } +} + +func (n *node[CHAIN_ID, HEAD, RPC]) syncingLoop() { + defer n.wg.Done() + + { + // sanity check + state := n.State() + switch state { + case nodeStateSyncing: + case nodeStateClosed: + return + default: + panic(fmt.Sprintf("syncingLoop can only run for node in nodeStateSyncing state, got: %s", state)) + } + } + + syncingAt := time.Now() + + lggr := logger.Sugared(logger.Named(n.lfcLog, "Syncing")) + lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with syncing status", n.String()), "nodeState", n.State()) + // Need to redial since syncing nodes are automatically disconnected + state := n.createVerifiedConn(n.nodeCtx, lggr) + if state != nodeStateSyncing { + n.declareState(state) + return + } + + recheckBackoff := iutils.NewRedialBackoff() + + for { + select { + case <-n.nodeCtx.Done(): + return + case <-time.After(recheckBackoff.Duration()): + lggr.Tracew("Trying to recheck if the node is still syncing", "nodeState", n.State()) + isSyncing, err := n.rpc.IsSyncing(n.nodeCtx) + if err != nil { + lggr.Errorw("Unexpected error while verifying RPC node synchronization status", "err", err, "nodeState", n.State()) n.declareUnreachable() return } - lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was offline for %s", time.Since(invalidAt)), "nodeState", n.State()) + + if isSyncing { + lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.State()) + continue + } + + lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was syncing for %s", time.Since(syncingAt)), "nodeState", n.State()) n.declareAlive() return } + } } diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index bf94e6bd063..7c31c085dd3 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -3,13 +3,14 @@ package client import ( "errors" "fmt" - big "math/big" + "math/big" "sync/atomic" "testing" "github.com/cometbft/cometbft/libs/rand" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -225,9 +226,11 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { // disconnects all on transfer to unreachable or outOfSync rpc.On("DisconnectAll").Maybe() // might be called in unreachable loop - rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + rpc.On("Dial", mock.Anything).Run(func(_ mock.Arguments) { + require.Equal(t, nodeStateOutOfSync, node.State()) + }).Return(errors.New("failed to dial")).Maybe() node.declareAlive() - tests.AssertLogEventually(t, observedLogs, "Failed to dial out-of-sync RPC node") + tests.AssertLogEventually(t, observedLogs, "Dial failed: Node is unreachable") }) t.Run("when behind more than SyncThreshold but we are the last live node, forcibly stays alive", func(t *testing.T) { t.Parallel() @@ -436,7 +439,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() outOfSyncSubscription := mocks.NewSubscription(t) @@ -471,7 +473,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return node.State() == nodeStateUnreachable }) }) - t.Run("if fail to get chainID, transitions to invalidChainID", func(t *testing.T) { + t.Run("if fail to get chainID, transitions to unreachable", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) node := newAliveNode(t, testNodeOpts{ @@ -479,13 +481,16 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { }) defer func() { assert.NoError(t, node.close()) }() + // for out-of-sync rpc.On("Dial", mock.Anything).Return(nil).Once() + // for unreachable + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() expectedError := errors.New("failed to get chain ID") // might be called multiple times rpc.On("ChainID", mock.Anything).Return(types.NewIDFromInt(0), expectedError) node.declareOutOfSync(stubIsOutOfSync) tests.AssertEventually(t, func() bool { - return node.State() == nodeStateInvalidChainID + return node.State() == nodeStateUnreachable }) }) t.Run("if chainID does not match, transitions to invalidChainID", func(t *testing.T) { @@ -499,7 +504,8 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { }) defer func() { assert.NoError(t, node.close()) }() - rpc.On("Dial", mock.Anything).Return(nil).Once() + // one for out-of-sync & one for invalid chainID + rpc.On("Dial", mock.Anything).Return(nil).Twice() // might be called multiple times rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) node.declareOutOfSync(stubIsOutOfSync) @@ -507,6 +513,49 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return node.State() == nodeStateInvalidChainID }) }) + t.Run("if syncing, transitions to syncing", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + // might be called multiple times + rpc.On("IsSyncing", mock.Anything).Return(true, nil) + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateSyncing + }) + }) + t.Run("if fails to fetch syncing status, transitions to unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + // one for out-of-sync + rpc.On("Dial", mock.Anything).Return(nil).Once() + // for unreachable + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + // might be called multiple times + rpc.On("IsSyncing", mock.Anything).Return(false, errors.New("failed to check syncing")) + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) t.Run("if fails to subscribe, becomes unreachable", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) @@ -518,7 +567,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() expectedError := errors.New("failed to subscribe") rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(nil, expectedError) @@ -541,7 +589,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() sub := mocks.NewSubscription(t) @@ -570,7 +617,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() sub := mocks.NewSubscription(t) @@ -601,7 +647,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() outOfSyncSubscription := mocks.NewSubscription(t) @@ -641,7 +686,6 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { } rpc.On("Dial", mock.Anything).Return(nil).Once() - // might be called multiple times rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() outOfSyncSubscription := mocks.NewSubscription(t) @@ -712,7 +756,7 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { assert.Equal(t, nodeStateDialed, node.State()) }).Return(nodeChainID, errors.New("failed to get chain id")) node.declareUnreachable() - tests.AssertLogCountEventually(t, observedLogs, "Failed to redial RPC node; verify failed", 2) + tests.AssertLogCountEventually(t, observedLogs, "Failed to verify chain ID for node", 2) }) t.Run("on chain ID mismatch transitions to invalidChainID", func(t *testing.T) { t.Parallel() @@ -732,7 +776,72 @@ func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { return node.State() == nodeStateInvalidChainID }) }) - t.Run("on valid chain ID becomes alive", func(t *testing.T) { + t.Run("on syncing status check failure, keeps trying", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateDialed, node.State()) + }).Return(nodeChainID, nil) + rpc.On("IsSyncing", mock.Anything).Return(false, errors.New("failed to check syncing status")) + node.declareUnreachable() + tests.AssertLogCountEventually(t, observedLogs, "Unexpected error while verifying RPC node synchronization status", 2) + }) + t.Run("on syncing, transitions to syncing state", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Twice() + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Twice() + rpc.On("IsSyncing", mock.Anything).Return(true, nil) + + setupRPCForAliveLoop(t, rpc) + + node.declareUnreachable() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateSyncing + }) + }) + t.Run("on successful verification becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + rpc.On("IsSyncing", mock.Anything).Return(false, nil) + + setupRPCForAliveLoop(t, rpc) + + node.declareUnreachable() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) + t.Run("on successful verification without isSyncing becomes alive", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() @@ -772,6 +881,22 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { node.invalidChainIDLoop() }) + t.Run("on invalid dial becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")) + node.declareInvalidChainID() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) t.Run("on failed chainID call becomes unreachable", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) @@ -785,10 +910,11 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() rpc.On("ChainID", mock.Anything).Return(nodeChainID, errors.New("failed to get chain id")) - // for unreachable loop + // once for chainID and maybe another one for unreachable + rpc.On("Dial", mock.Anything).Return(nil).Once() rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() node.declareInvalidChainID() - tests.AssertLogEventually(t, observedLogs, "Unexpected error while verifying RPC node chain ID") + tests.AssertLogEventually(t, observedLogs, "Failed to verify chain ID for node") tests.AssertEventually(t, func() bool { return node.State() == nodeStateUnreachable }) @@ -806,6 +932,7 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { }) defer func() { assert.NoError(t, node.close()) }() + rpc.On("Dial", mock.Anything).Return(nil).Once() rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) node.declareInvalidChainID() tests.AssertLogCountEventually(t, observedLogs, "Failed to verify RPC node; remote endpoint returned the wrong chain ID", 2) @@ -813,17 +940,44 @@ func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { return node.State() == nodeStateInvalidChainID }) }) - t.Run("on valid chainID becomes alive", func(t *testing.T) { + t.Run("on successful verification without isSyncing becomes alive", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) - nodeChainID := types.RandomID() + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) node := newDialedNode(t, testNodeOpts{ rpc: rpc, chainID: nodeChainID, }) defer func() { assert.NoError(t, node.close()) }() - rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil).Once() + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + setupRPCForAliveLoop(t, rpc) + + node.declareInvalidChainID() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) + t.Run("on successful verification becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil).Once() + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(false, nil).Once() setupRPCForAliveLoop(t, rpc) @@ -885,7 +1039,7 @@ func TestUnit_NodeLifecycle_start(t *testing.T) { rpc.On("DisconnectAll") err := node.Start(tests.Context(t)) assert.NoError(t, err) - tests.AssertLogEventually(t, observedLogs, "Verify failed") + tests.AssertLogEventually(t, observedLogs, "Failed to verify chain ID for node") tests.AssertEventually(t, func() bool { return node.State() == nodeStateUnreachable }) @@ -911,7 +1065,81 @@ func TestUnit_NodeLifecycle_start(t *testing.T) { return node.State() == nodeStateInvalidChainID }) }) - t.Run("on valid chain ID becomes alive", func(t *testing.T) { + t.Run("if syncing verification fails, becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("ChainID", mock.Anything).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateDialed, node.State()) + }).Return(nodeChainID, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(false, errors.New("failed to check syncing status")) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll") + // fail to redial to stay in unreachable state + rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")) + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertLogEventually(t, observedLogs, "Unexpected error while verifying RPC node synchronization status") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on isSyncing transitions to syncing", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + rpc.On("IsSyncing", mock.Anything).Return(true, nil) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll") + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateSyncing + }) + }) + t.Run("on successful verification becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + config: testNodeConfig{nodeIsSyncingEnabled: true}, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + rpc.On("IsSyncing", mock.Anything).Return(false, nil) + + setupRPCForAliveLoop(t, rpc) + + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) + t.Run("on successful verification without isSyncing becomes alive", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) nodeChainID := types.RandomID() @@ -1069,3 +1297,150 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { }) } + +func TestUnit_NodeLifecycle_SyncingLoop(t *testing.T) { + t.Parallel() + newDialedNode := func(t *testing.T, opts testNodeOpts) testNode { + opts.config.nodeIsSyncingEnabled = true + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + opts.rpc.On("DisconnectAll") + + node.setState(nodeStateDialed) + return node + } + t.Run("returns on closed", func(t *testing.T) { + t.Parallel() + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateClosed) + node.wg.Add(1) + node.syncingLoop() + + }) + t.Run("on invalid dial becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")) + node.declareSyncing() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on failed chainID call becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(nodeChainID, errors.New("failed to get chain id")) + // once for syncing and maybe another one for unreachable + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareSyncing() + tests.AssertLogEventually(t, observedLogs, "Failed to verify chain ID for node") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on chainID mismatch transitions to invalidChainID", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Twice() + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) + node.declareSyncing() + tests.AssertLogCountEventually(t, observedLogs, "Failed to verify RPC node; remote endpoint returned the wrong chain ID", 2) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("on failed Syncing check - becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + // first one is needed to enter internal loop + rpc.On("IsSyncing", mock.Anything).Return(true, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(false, errors.New("failed to check if syncing")).Once() + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareSyncing() + tests.AssertLogEventually(t, observedLogs, "Unexpected error while verifying RPC node synchronization status") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on IsSyncing - keeps trying", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(true, nil) + rpc.On("Dial", mock.Anything).Return(nil).Once() + node.declareSyncing() + tests.AssertLogCountEventually(t, observedLogs, "Verification failed: Node is syncing", 2) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateSyncing + }) + }) + t.Run("on successful verification becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(true, nil).Once() + rpc.On("IsSyncing", mock.Anything).Return(false, nil).Once() + + setupRPCForAliveLoop(t, rpc) + + node.declareSyncing() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) +} diff --git a/common/client/node_test.go b/common/client/node_test.go index 7b6a38e3951..c7a7a710d8f 100644 --- a/common/client/node_test.go +++ b/common/client/node_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -14,6 +15,7 @@ type testNodeConfig struct { pollInterval time.Duration selectionMode string syncThreshold uint32 + nodeIsSyncingEnabled bool } func (n testNodeConfig) PollFailureThreshold() uint32 { @@ -32,6 +34,10 @@ func (n testNodeConfig) SyncThreshold() uint32 { return n.syncThreshold } +func (n testNodeConfig) NodeIsSyncingEnabled() bool { + return n.nodeIsSyncingEnabled +} + type testNode struct { *node[types.ID, Head, NodeClient[types.ID, Head]] } diff --git a/common/client/types.go b/common/client/types.go index c05ab238f57..485a0b2671a 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/smartcontractkit/chainlink-common/pkg/assets" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -70,6 +71,7 @@ type NodeClient[ SubscribersCount() int32 SetAliveLoopSub(types.Subscription) UnsubscribeAllExceptAliveLoop() + IsSyncing(ctx context.Context) (bool, error) } // clientAPI includes all the direct RPC methods required by the generalized common client to implement its own. diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 33deed1df32..cd4665aac8c 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -35,7 +35,7 @@ type chainClient struct { *evmtypes.Receipt, *assets.Wei, *evmtypes.Head, - RPCCLient, + RPCClient, rpc.BatchElem, ] logger logger.SugaredLogger @@ -46,8 +46,8 @@ func NewChainClient( selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, - nodes []commonclient.Node[*big.Int, *evmtypes.Head, RPCCLient], - sendonlys []commonclient.SendOnlyNode[*big.Int, RPCCLient], + nodes []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient], + sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient], chainID *big.Int, chainType config.ChainType, ) Client { @@ -63,7 +63,7 @@ func NewChainClient( *evmtypes.Receipt, *assets.Wei, *evmtypes.Head, - RPCCLient, + RPCClient, ]( lggr, selectionMode, diff --git a/core/chains/evm/client/chain_client_test.go b/core/chains/evm/client/chain_client_test.go index 6af9a67ee1c..1718036641e 100644 --- a/core/chains/evm/client/chain_client_test.go +++ b/core/chains/evm/client/chain_client_test.go @@ -18,8 +18,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) -func newMockRpc(t *testing.T) *mocks.RPCCLient { - mockRpc := mocks.NewRPCCLient(t) +func newMockRpc(t *testing.T) *mocks.RPCClient { + mockRpc := mocks.NewRPCClient(t) mockRpc.On("Dial", mock.Anything).Return(nil).Once() mockRpc.On("Close").Return(nil).Once() mockRpc.On("ChainID", mock.Anything).Return(testutils.FixtureChainID, nil).Once() diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 467195e11e8..c1652c19c26 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -22,6 +23,7 @@ type TestNodePoolConfig struct { NodeSelectionMode string NodeSyncThreshold uint32 NodeLeaseDuration time.Duration + NodeIsSyncingEnabledVal bool } func (tc TestNodePoolConfig) PollFailureThreshold() uint32 { return tc.NodePollFailureThreshold } @@ -32,6 +34,10 @@ func (tc TestNodePoolConfig) LeaseDuration() time.Duration { return tc.NodeLeaseDuration } +func (tc TestNodePoolConfig) NodeIsSyncingEnabled() bool { + return tc.NodeIsSyncingEnabledVal +} + func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeadsThreshold time.Duration, rpcUrl string, rpcHTTPURL *url.URL, sendonlyRPCURLs []url.URL, id int32, chainID *big.Int) (*client, error) { parsed, err := url.ParseRequestURI(rpcUrl) if err != nil { @@ -89,18 +95,18 @@ func NewChainClientWithTestNode( lggr := logger.Test(t) rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary) - n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCCLient]( + n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCClient]( nodeCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM") - primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCCLient]{n} + primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]{n} - var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCCLient] + var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient] for i, u := range sendonlyRPCURLs { if u.Scheme != "http" && u.Scheme != "https" { return nil, errors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String()) } var empty url.URL rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, commonclient.Secondary) - s := commonclient.NewSendOnlyNode[*big.Int, RPCCLient]( + s := commonclient.NewSendOnlyNode[*big.Int, RPCClient]( lggr, u, fmt.Sprintf("eth-sendonly-%d", i), chainID, rpc) sendonlys = append(sendonlys, s) } @@ -133,7 +139,7 @@ func NewChainClientWithMockedRpc( leaseDuration time.Duration, noNewHeadsThreshold time.Duration, chainID *big.Int, - rpc RPCCLient, + rpc RPCClient, ) Client { lggr := logger.Test(t) @@ -145,9 +151,9 @@ func NewChainClientWithMockedRpc( } parsed, _ := url.ParseRequestURI("ws://test") - n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCCLient]( + n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCClient]( cfg, noNewHeadsThreshold, lggr, *parsed, nil, "eth-primary-node-0", 1, chainID, 1, rpc, "EVM") - primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCCLient]{n} + primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]{n} c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaries, nil, chainID, chainType) t.Cleanup(c.Close) return c diff --git a/core/chains/evm/client/mocks/rpc_client.go b/core/chains/evm/client/mocks/rpc_client.go index 186fd2534e3..26d5744a1ab 100644 --- a/core/chains/evm/client/mocks/rpc_client.go +++ b/core/chains/evm/client/mocks/rpc_client.go @@ -26,13 +26,13 @@ import ( types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) -// RPCCLient is an autogenerated mock type for the RPCCLient type -type RPCCLient struct { +// RPCClient is an autogenerated mock type for the RPCClient type +type RPCClient struct { mock.Mock } // BalanceAt provides a mock function with given fields: ctx, accountAddress, blockNumber -func (_m *RPCCLient) BalanceAt(ctx context.Context, accountAddress common.Address, blockNumber *big.Int) (*big.Int, error) { +func (_m *RPCClient) BalanceAt(ctx context.Context, accountAddress common.Address, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, accountAddress, blockNumber) if len(ret) == 0 { @@ -62,7 +62,7 @@ func (_m *RPCCLient) BalanceAt(ctx context.Context, accountAddress common.Addres } // BatchCallContext provides a mock function with given fields: ctx, b -func (_m *RPCCLient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { +func (_m *RPCClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) if len(ret) == 0 { @@ -80,7 +80,7 @@ func (_m *RPCCLient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) er } // BlockByHash provides a mock function with given fields: ctx, hash -func (_m *RPCCLient) BlockByHash(ctx context.Context, hash common.Hash) (*types.Head, error) { +func (_m *RPCClient) BlockByHash(ctx context.Context, hash common.Hash) (*types.Head, error) { ret := _m.Called(ctx, hash) if len(ret) == 0 { @@ -110,7 +110,7 @@ func (_m *RPCCLient) BlockByHash(ctx context.Context, hash common.Hash) (*types. } // BlockByHashGeth provides a mock function with given fields: ctx, hash -func (_m *RPCCLient) BlockByHashGeth(ctx context.Context, hash common.Hash) (*coretypes.Block, error) { +func (_m *RPCClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (*coretypes.Block, error) { ret := _m.Called(ctx, hash) if len(ret) == 0 { @@ -140,7 +140,7 @@ func (_m *RPCCLient) BlockByHashGeth(ctx context.Context, hash common.Hash) (*co } // BlockByNumber provides a mock function with given fields: ctx, number -func (_m *RPCCLient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Head, error) { +func (_m *RPCClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Head, error) { ret := _m.Called(ctx, number) if len(ret) == 0 { @@ -170,7 +170,7 @@ func (_m *RPCCLient) BlockByNumber(ctx context.Context, number *big.Int) (*types } // BlockByNumberGeth provides a mock function with given fields: ctx, number -func (_m *RPCCLient) BlockByNumberGeth(ctx context.Context, number *big.Int) (*coretypes.Block, error) { +func (_m *RPCClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (*coretypes.Block, error) { ret := _m.Called(ctx, number) if len(ret) == 0 { @@ -200,7 +200,7 @@ func (_m *RPCCLient) BlockByNumberGeth(ctx context.Context, number *big.Int) (*c } // CallContext provides a mock function with given fields: ctx, result, method, args -func (_m *RPCCLient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { +func (_m *RPCClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { var _ca []interface{} _ca = append(_ca, ctx, result, method) _ca = append(_ca, args...) @@ -221,7 +221,7 @@ func (_m *RPCCLient) CallContext(ctx context.Context, result interface{}, method } // CallContract provides a mock function with given fields: ctx, msg, blockNumber -func (_m *RPCCLient) CallContract(ctx context.Context, msg interface{}, blockNumber *big.Int) ([]byte, error) { +func (_m *RPCClient) CallContract(ctx context.Context, msg interface{}, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) if len(ret) == 0 { @@ -251,7 +251,7 @@ func (_m *RPCCLient) CallContract(ctx context.Context, msg interface{}, blockNum } // ChainID provides a mock function with given fields: ctx -func (_m *RPCCLient) ChainID(ctx context.Context) (*big.Int, error) { +func (_m *RPCClient) ChainID(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) if len(ret) == 0 { @@ -281,7 +281,7 @@ func (_m *RPCCLient) ChainID(ctx context.Context) (*big.Int, error) { } // ClientVersion provides a mock function with given fields: _a0 -func (_m *RPCCLient) ClientVersion(_a0 context.Context) (string, error) { +func (_m *RPCClient) ClientVersion(_a0 context.Context) (string, error) { ret := _m.Called(_a0) if len(ret) == 0 { @@ -309,12 +309,12 @@ func (_m *RPCCLient) ClientVersion(_a0 context.Context) (string, error) { } // Close provides a mock function with given fields: -func (_m *RPCCLient) Close() { +func (_m *RPCClient) Close() { _m.Called() } // CodeAt provides a mock function with given fields: ctx, account, blockNumber -func (_m *RPCCLient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { +func (_m *RPCClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) if len(ret) == 0 { @@ -344,7 +344,7 @@ func (_m *RPCCLient) CodeAt(ctx context.Context, account common.Address, blockNu } // Dial provides a mock function with given fields: ctx -func (_m *RPCCLient) Dial(ctx context.Context) error { +func (_m *RPCClient) Dial(ctx context.Context) error { ret := _m.Called(ctx) if len(ret) == 0 { @@ -362,7 +362,7 @@ func (_m *RPCCLient) Dial(ctx context.Context) error { } // DialHTTP provides a mock function with given fields: -func (_m *RPCCLient) DialHTTP() error { +func (_m *RPCClient) DialHTTP() error { ret := _m.Called() if len(ret) == 0 { @@ -380,12 +380,12 @@ func (_m *RPCCLient) DialHTTP() error { } // DisconnectAll provides a mock function with given fields: -func (_m *RPCCLient) DisconnectAll() { +func (_m *RPCClient) DisconnectAll() { _m.Called() } // EstimateGas provides a mock function with given fields: ctx, call -func (_m *RPCCLient) EstimateGas(ctx context.Context, call interface{}) (uint64, error) { +func (_m *RPCClient) EstimateGas(ctx context.Context, call interface{}) (uint64, error) { ret := _m.Called(ctx, call) if len(ret) == 0 { @@ -413,7 +413,7 @@ func (_m *RPCCLient) EstimateGas(ctx context.Context, call interface{}) (uint64, } // FilterEvents provides a mock function with given fields: ctx, query -func (_m *RPCCLient) FilterEvents(ctx context.Context, query ethereum.FilterQuery) ([]coretypes.Log, error) { +func (_m *RPCClient) FilterEvents(ctx context.Context, query ethereum.FilterQuery) ([]coretypes.Log, error) { ret := _m.Called(ctx, query) if len(ret) == 0 { @@ -443,7 +443,7 @@ func (_m *RPCCLient) FilterEvents(ctx context.Context, query ethereum.FilterQuer } // HeaderByHash provides a mock function with given fields: ctx, h -func (_m *RPCCLient) HeaderByHash(ctx context.Context, h common.Hash) (*coretypes.Header, error) { +func (_m *RPCClient) HeaderByHash(ctx context.Context, h common.Hash) (*coretypes.Header, error) { ret := _m.Called(ctx, h) if len(ret) == 0 { @@ -473,7 +473,7 @@ func (_m *RPCCLient) HeaderByHash(ctx context.Context, h common.Hash) (*coretype } // HeaderByNumber provides a mock function with given fields: ctx, n -func (_m *RPCCLient) HeaderByNumber(ctx context.Context, n *big.Int) (*coretypes.Header, error) { +func (_m *RPCClient) HeaderByNumber(ctx context.Context, n *big.Int) (*coretypes.Header, error) { ret := _m.Called(ctx, n) if len(ret) == 0 { @@ -502,8 +502,36 @@ func (_m *RPCCLient) HeaderByNumber(ctx context.Context, n *big.Int) (*coretypes return r0, r1 } +// IsSyncing provides a mock function with given fields: ctx +func (_m *RPCClient) IsSyncing(ctx context.Context) (bool, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for IsSyncing") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // LINKBalance provides a mock function with given fields: ctx, accountAddress, linkAddress -func (_m *RPCCLient) LINKBalance(ctx context.Context, accountAddress common.Address, linkAddress common.Address) (*assets.Link, error) { +func (_m *RPCClient) LINKBalance(ctx context.Context, accountAddress common.Address, linkAddress common.Address) (*assets.Link, error) { ret := _m.Called(ctx, accountAddress, linkAddress) if len(ret) == 0 { @@ -533,7 +561,7 @@ func (_m *RPCCLient) LINKBalance(ctx context.Context, accountAddress common.Addr } // LatestBlockHeight provides a mock function with given fields: _a0 -func (_m *RPCCLient) LatestBlockHeight(_a0 context.Context) (*big.Int, error) { +func (_m *RPCClient) LatestBlockHeight(_a0 context.Context) (*big.Int, error) { ret := _m.Called(_a0) if len(ret) == 0 { @@ -563,7 +591,7 @@ func (_m *RPCCLient) LatestBlockHeight(_a0 context.Context) (*big.Int, error) { } // PendingCallContract provides a mock function with given fields: ctx, msg -func (_m *RPCCLient) PendingCallContract(ctx context.Context, msg interface{}) ([]byte, error) { +func (_m *RPCClient) PendingCallContract(ctx context.Context, msg interface{}) ([]byte, error) { ret := _m.Called(ctx, msg) if len(ret) == 0 { @@ -593,7 +621,7 @@ func (_m *RPCCLient) PendingCallContract(ctx context.Context, msg interface{}) ( } // PendingCodeAt provides a mock function with given fields: ctx, account -func (_m *RPCCLient) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { +func (_m *RPCClient) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { ret := _m.Called(ctx, account) if len(ret) == 0 { @@ -623,7 +651,7 @@ func (_m *RPCCLient) PendingCodeAt(ctx context.Context, account common.Address) } // PendingSequenceAt provides a mock function with given fields: ctx, addr -func (_m *RPCCLient) PendingSequenceAt(ctx context.Context, addr common.Address) (types.Nonce, error) { +func (_m *RPCClient) PendingSequenceAt(ctx context.Context, addr common.Address) (types.Nonce, error) { ret := _m.Called(ctx, addr) if len(ret) == 0 { @@ -651,7 +679,7 @@ func (_m *RPCCLient) PendingSequenceAt(ctx context.Context, addr common.Address) } // SendEmptyTransaction provides a mock function with given fields: ctx, newTxAttempt, seq, gasLimit, fee, fromAddress -func (_m *RPCCLient) SendEmptyTransaction(ctx context.Context, newTxAttempt func(types.Nonce, uint32, *evmassets.Wei, common.Address) (interface{}, error), seq types.Nonce, gasLimit uint32, fee *evmassets.Wei, fromAddress common.Address) (string, error) { +func (_m *RPCClient) SendEmptyTransaction(ctx context.Context, newTxAttempt func(types.Nonce, uint32, *evmassets.Wei, common.Address) (interface{}, error), seq types.Nonce, gasLimit uint32, fee *evmassets.Wei, fromAddress common.Address) (string, error) { ret := _m.Called(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) if len(ret) == 0 { @@ -679,7 +707,7 @@ func (_m *RPCCLient) SendEmptyTransaction(ctx context.Context, newTxAttempt func } // SendTransaction provides a mock function with given fields: ctx, tx -func (_m *RPCCLient) SendTransaction(ctx context.Context, tx *coretypes.Transaction) error { +func (_m *RPCClient) SendTransaction(ctx context.Context, tx *coretypes.Transaction) error { ret := _m.Called(ctx, tx) if len(ret) == 0 { @@ -697,7 +725,7 @@ func (_m *RPCCLient) SendTransaction(ctx context.Context, tx *coretypes.Transact } // SequenceAt provides a mock function with given fields: ctx, accountAddress, blockNumber -func (_m *RPCCLient) SequenceAt(ctx context.Context, accountAddress common.Address, blockNumber *big.Int) (types.Nonce, error) { +func (_m *RPCClient) SequenceAt(ctx context.Context, accountAddress common.Address, blockNumber *big.Int) (types.Nonce, error) { ret := _m.Called(ctx, accountAddress, blockNumber) if len(ret) == 0 { @@ -725,12 +753,12 @@ func (_m *RPCCLient) SequenceAt(ctx context.Context, accountAddress common.Addre } // SetAliveLoopSub provides a mock function with given fields: _a0 -func (_m *RPCCLient) SetAliveLoopSub(_a0 commontypes.Subscription) { +func (_m *RPCClient) SetAliveLoopSub(_a0 commontypes.Subscription) { _m.Called(_a0) } // SimulateTransaction provides a mock function with given fields: ctx, tx -func (_m *RPCCLient) SimulateTransaction(ctx context.Context, tx *coretypes.Transaction) error { +func (_m *RPCClient) SimulateTransaction(ctx context.Context, tx *coretypes.Transaction) error { ret := _m.Called(ctx, tx) if len(ret) == 0 { @@ -748,7 +776,7 @@ func (_m *RPCCLient) SimulateTransaction(ctx context.Context, tx *coretypes.Tran } // Subscribe provides a mock function with given fields: ctx, channel, args -func (_m *RPCCLient) Subscribe(ctx context.Context, channel chan<- *types.Head, args ...interface{}) (commontypes.Subscription, error) { +func (_m *RPCClient) Subscribe(ctx context.Context, channel chan<- *types.Head, args ...interface{}) (commontypes.Subscription, error) { var _ca []interface{} _ca = append(_ca, ctx, channel) _ca = append(_ca, args...) @@ -781,7 +809,7 @@ func (_m *RPCCLient) Subscribe(ctx context.Context, channel chan<- *types.Head, } // SubscribeFilterLogs provides a mock function with given fields: ctx, q, ch -func (_m *RPCCLient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- coretypes.Log) (ethereum.Subscription, error) { +func (_m *RPCClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- coretypes.Log) (ethereum.Subscription, error) { ret := _m.Called(ctx, q, ch) if len(ret) == 0 { @@ -811,7 +839,7 @@ func (_m *RPCCLient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQ } // SubscribersCount provides a mock function with given fields: -func (_m *RPCCLient) SubscribersCount() int32 { +func (_m *RPCClient) SubscribersCount() int32 { ret := _m.Called() if len(ret) == 0 { @@ -829,7 +857,7 @@ func (_m *RPCCLient) SubscribersCount() int32 { } // SuggestGasPrice provides a mock function with given fields: ctx -func (_m *RPCCLient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { +func (_m *RPCClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) if len(ret) == 0 { @@ -859,7 +887,7 @@ func (_m *RPCCLient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { } // SuggestGasTipCap provides a mock function with given fields: ctx -func (_m *RPCCLient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { +func (_m *RPCClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) if len(ret) == 0 { @@ -889,7 +917,7 @@ func (_m *RPCCLient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { } // TokenBalance provides a mock function with given fields: ctx, accountAddress, tokenAddress -func (_m *RPCCLient) TokenBalance(ctx context.Context, accountAddress common.Address, tokenAddress common.Address) (*big.Int, error) { +func (_m *RPCClient) TokenBalance(ctx context.Context, accountAddress common.Address, tokenAddress common.Address) (*big.Int, error) { ret := _m.Called(ctx, accountAddress, tokenAddress) if len(ret) == 0 { @@ -919,7 +947,7 @@ func (_m *RPCCLient) TokenBalance(ctx context.Context, accountAddress common.Add } // TransactionByHash provides a mock function with given fields: ctx, txHash -func (_m *RPCCLient) TransactionByHash(ctx context.Context, txHash common.Hash) (*coretypes.Transaction, error) { +func (_m *RPCClient) TransactionByHash(ctx context.Context, txHash common.Hash) (*coretypes.Transaction, error) { ret := _m.Called(ctx, txHash) if len(ret) == 0 { @@ -949,7 +977,7 @@ func (_m *RPCCLient) TransactionByHash(ctx context.Context, txHash common.Hash) } // TransactionReceipt provides a mock function with given fields: ctx, txHash -func (_m *RPCCLient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { +func (_m *RPCClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { ret := _m.Called(ctx, txHash) if len(ret) == 0 { @@ -979,7 +1007,7 @@ func (_m *RPCCLient) TransactionReceipt(ctx context.Context, txHash common.Hash) } // TransactionReceiptGeth provides a mock function with given fields: ctx, txHash -func (_m *RPCCLient) TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (*coretypes.Receipt, error) { +func (_m *RPCClient) TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (*coretypes.Receipt, error) { ret := _m.Called(ctx, txHash) if len(ret) == 0 { @@ -1009,17 +1037,17 @@ func (_m *RPCCLient) TransactionReceiptGeth(ctx context.Context, txHash common.H } // UnsubscribeAllExceptAliveLoop provides a mock function with given fields: -func (_m *RPCCLient) UnsubscribeAllExceptAliveLoop() { +func (_m *RPCClient) UnsubscribeAllExceptAliveLoop() { _m.Called() } -// NewRPCCLient creates a new instance of RPCCLient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewRPCClient creates a new instance of RPCClient. 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 NewRPCCLient(t interface { +func NewRPCClient(t interface { mock.TestingT Cleanup(func()) -}) *RPCCLient { - mock := &RPCCLient{} +}) *RPCClient { + mock := &RPCClient{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 08791658430..d71762ac09a 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -29,8 +29,10 @@ import ( 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. -type RPCCLient interface { +// RPCClient includes all the necessary generalized RPC methods along with any additional chain-specific methods. +// +//go:generate mockery --quiet --name RPCClient --output ./mocks --case=underscore +type RPCClient interface { commonclient.RPC[ *big.Int, evmtypes.Nonce, @@ -90,7 +92,7 @@ func NewRPCClient( id int32, chainID *big.Int, tier commonclient.NodeTier, -) RPCCLient { +) RPCClient { r := new(rpcClient) r.name = name r.id = id @@ -1106,6 +1108,33 @@ func (r *rpcClient) makeQueryCtx(ctx context.Context) (context.Context, context. return makeQueryCtx(ctx, r.getChStopInflight()) } +func (r *rpcClient) IsSyncing(ctx context.Context) (bool, error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return false, err + } + defer cancel() + lggr := r.newRqLggr() + + lggr.Debug("RPC call: evmclient.Client#SyncProgress") + var syncProgress *ethereum.SyncProgress + start := time.Now() + if http != nil { + syncProgress, err = http.geth.SyncProgress(ctx) + err = r.wrapHTTP(err) + } else { + syncProgress, err = ws.geth.SyncProgress(ctx) + err = r.wrapWS(err) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "BlockNumber", + "syncProgress", syncProgress, + ) + + return syncProgress != nil, nil +} + // getChStopInflight provides a convenience helper that mutex wraps a // read to the chStopInFlight func (r *rpcClient) getChStopInflight() chan struct{} { diff --git a/core/chains/evm/config/chain_scoped_node_pool.go b/core/chains/evm/config/chain_scoped_node_pool.go index 8244d620a53..fc52caa0aa3 100644 --- a/core/chains/evm/config/chain_scoped_node_pool.go +++ b/core/chains/evm/config/chain_scoped_node_pool.go @@ -29,3 +29,7 @@ func (n *nodePoolConfig) SyncThreshold() uint32 { func (n *nodePoolConfig) LeaseDuration() time.Duration { return n.c.LeaseDuration.Duration() } + +func (n *nodePoolConfig) NodeIsSyncingEnabled() bool { + return *n.c.NodeIsSyncingEnabled +} diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index 2cfc497f462..cb1a6073e0b 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -139,6 +139,7 @@ type NodePool interface { SelectionMode() string SyncThreshold() uint32 LeaseDuration() time.Duration + NodeIsSyncingEnabled() bool } // TODO BCF-2509 does the chainscopedconfig really need the entire app config? diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index cd1967b9582..f62f540dafc 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -12,6 +12,7 @@ import ( "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" @@ -474,6 +475,7 @@ func TestNodePoolConfig(t *testing.T) { require.Equal(t, uint32(5), cfg.EVM().NodePool().SyncThreshold()) require.Equal(t, time.Duration(10000000000), cfg.EVM().NodePool().PollInterval()) require.Equal(t, uint32(5), cfg.EVM().NodePool().PollFailureThreshold()) + require.Equal(t, false, cfg.EVM().NodePool().NodeIsSyncingEnabled()) } func ptr[T any](t T) *T { return &t } diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 0ffe3549613..95b6c342161 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -705,6 +705,7 @@ type NodePool struct { SelectionMode *string SyncThreshold *uint32 LeaseDuration *commonconfig.Duration + NodeIsSyncingEnabled *bool } func (p *NodePool) setFrom(f *NodePool) { @@ -723,6 +724,9 @@ func (p *NodePool) setFrom(f *NodePool) { if v := f.LeaseDuration; v != nil { p.LeaseDuration = v } + if v := f.NodeIsSyncingEnabled; v != nil { + p.NodeIsSyncingEnabled = v + } } type OCR struct { diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml index 7b369142133..8587a5b4b20 100644 --- a/core/chains/evm/config/toml/defaults/fallback.toml +++ b/core/chains/evm/config/toml/defaults/fallback.toml @@ -60,6 +60,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 66907b8352f..4e0344281cf 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -471,19 +471,19 @@ func (c *chain) GasEstimator() gas.EvmFeeEstimator { return c.gasEstimato func newEthClientFromCfg(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) evmclient.Client { var empty url.URL - var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient] - var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] + var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCClient] + var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCClient] for i, node := range nodes { if node.SendOnly != nil && *node.SendOnly { 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), + sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCClient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc) sendonlys = append(sendonlys, sendonly) } else { 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, + 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, rpc, "EVM") primaries = append(primaries, primaryNode) diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index eec580a8e69..f70dcd0ee45 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -332,6 +332,12 @@ SyncThreshold = 5 # Default # # Set to '0s' to disable LeaseDuration = '0s' # Default +# NodeIsSyncingEnabled is a flag that enables `syncing` health check on each reconnection to an RPC. +# Node transitions and remains in `Syncing` state while RPC signals this state (In case of Ethereum `eth_syncing` returns anything other than false). +# All of the requests to node in state `Syncing` are rejected. +# +# Set true to enable this check +NodeIsSyncingEnabled = false # Default [EVM.OCR] # ContractConfirmations sets `OCR.ContractConfirmations` for this EVM chain. diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index a38b4707179..9fdd50625cc 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -290,6 +290,8 @@ func (ts *testWSServer) newWSHandler(chainID *big.Int, callback JSONRPCHandler) var resp JSONRPCResponse if chainID != nil && m.String() == "eth_chainId" { resp.Result = `"0x` + chainID.Text(16) + `"` + } else if m.String() == "eth_syncing" { + resp.Result = "false" } else { resp = callback(m.String(), req.Get("params")) } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 13e18145e73..ed252eadd97 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -559,6 +559,7 @@ func TestConfig_Marshal(t *testing.T) { SelectionMode: &selectionMode, SyncThreshold: ptr[uint32](13), LeaseDuration: &zeroSeconds, + NodeIsSyncingEnabled: ptr(true), }, OCR: evmcfg.OCR{ ContractConfirmations: ptr[uint16](11), @@ -995,6 +996,7 @@ PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' +NodeIsSyncingEnabled = true [EVM.OCR] ContractConfirmations = 11 diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index fc47602ef3b..e90f6c6611a 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -324,6 +324,7 @@ PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' +NodeIsSyncingEnabled = true [EVM.OCR] ContractConfirmations = 11 diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 2ad6bf30c50..c230a764c74 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -295,6 +295,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 @@ -383,6 +384,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 @@ -465,6 +467,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 2c84024cde6..f698f55fb25 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -323,6 +323,7 @@ PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 11 diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 2ad6bf30c50..c230a764c74 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -295,6 +295,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 @@ -383,6 +384,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 @@ -465,6 +467,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0d1a5cc365e..fbb08016552 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Gas bumping logic to the `SuggestedPriceEstimator`. The bumping mechanism for this estimator refetches the price from the RPC and adds a buffer on top using the greater of `BumpPercent` and `BumpMin`. +- Added a new configuration field named `NodeIsSyncingEnabled` for `EVM.NodePool` that will check on every reconnection to an RPC if it's syncing and should not be transitioned to `Alive` state. Disabled by default. - Add preliminary support for "llo" job type (Data Streams V1) - Add `LogPrunePageSize` parameter to the EVM configuration. This parameter controls the number of logs removed during prune phase in LogPoller. Default value is 0, which deletes all logs at once - exactly how it used to work, so it doesn't require any changes on the product's side. - Add Juels Fee Per Coin data source caching for OCR2 Feeds. Cache is time based and is turned on by default with default cache refresh of 5 minutes. Cache can be configured through pluginconfig using "juelsPerFeeCoinCacheDuration" and "juelsPerFeeCoinCacheDisabled" tags. Duration tag accepts values between "30s" and "20m" with default of "0s" that is overridden on cache startup to 5 minutes. diff --git a/docs/CONFIG.md b/docs/CONFIG.md index baafab0d347..e4e25e6694f 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1658,6 +1658,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -1740,6 +1741,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -1822,6 +1824,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -1904,6 +1907,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -1987,6 +1991,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -2069,6 +2074,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2151,6 +2157,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2234,6 +2241,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2316,6 +2324,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2397,6 +2406,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2478,6 +2488,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2560,6 +2571,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2643,6 +2655,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2725,6 +2738,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2807,6 +2821,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2889,6 +2904,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -2971,6 +2987,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3053,6 +3070,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -3135,6 +3153,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -3218,6 +3237,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3300,6 +3320,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3381,6 +3402,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3463,6 +3485,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3544,6 +3567,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3626,6 +3650,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3708,6 +3733,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3789,6 +3815,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3870,6 +3897,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -3952,6 +3980,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4034,6 +4063,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -4115,6 +4145,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4197,6 +4228,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4279,6 +4311,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -4362,6 +4395,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4444,6 +4478,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4526,6 +4561,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4608,6 +4644,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4690,6 +4727,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -4771,6 +4809,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -4852,6 +4891,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -4934,6 +4974,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -5016,6 +5057,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5098,6 +5140,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5181,6 +5224,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5264,6 +5308,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5346,6 +5391,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5428,6 +5474,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5510,6 +5557,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 1 @@ -5592,6 +5640,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -5674,6 +5723,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -5756,6 +5806,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [OCR] ContractConfirmations = 4 @@ -6389,6 +6440,7 @@ PollInterval = '10s' # Default SelectionMode = 'HighestHead' # Default SyncThreshold = 5 # Default LeaseDuration = '0s' # Default +NodeIsSyncingEnabled = false # Default ``` The node pool manages multiple RPC endpoints. @@ -6440,6 +6492,16 @@ Recommended value is over 5m Set to '0s' to disable +### NodeIsSyncingEnabled +```toml +NodeIsSyncingEnabled = false # Default +``` +NodeIsSyncingEnabled is a flag that enables `syncing` health check on each reconnection to an RPC. +Node transitions and remains in `Syncing` state while RPC signals this state (In case of Ethereum `eth_syncing` returns anything other than false). +All of the requests to node in state `Syncing` are rejected. + +Set true to enable this check + ## EVM.OCR ```toml [EVM.OCR] diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index be61aef4898..bb845b05201 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -351,6 +351,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 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 bf39b7d8394..cdac1b3702c 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -351,6 +351,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 0ef1c6a7132..832b3fac584 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -351,6 +351,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index e4eccf9895a..280fa209f0d 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -341,6 +341,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 9c1026d7f4c..bdd83a9eb31 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -348,6 +348,7 @@ PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' +NodeIsSyncingEnabled = false [EVM.OCR] ContractConfirmations = 4 From 0081ed66fa0e0e5be332c0401dc730541aff451e Mon Sep 17 00:00:00 2001 From: Sneha Agnihotri <180277+snehaagni@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:37:52 -0800 Subject: [PATCH 15/20] release/2.9.0 -> develop (#12150) * move the error to after confirming it is intended to use mercury (#11897) (#11904) (cherry picked from commit 56e24d629d0c6382c2cb5476cfe3a9c1b8d0d182) * do not call an RPC if it's not Alive (#11999) (cherry picked from commit e78d3b81fa50dc05d3f7b6c2777a9dbc8a00f1ad) * Finalize date on changelog for $VERSION Signed-off-by: Sneha Agnihotri * remove streams from sonar coverage * Remove merge artifact in multi_node_test.go --------- Signed-off-by: Sneha Agnihotri Co-authored-by: Lei Co-authored-by: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> --- docs/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fbb08016552..ad7903a33f8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -25,7 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Minimum required version of Postgres is now >= 12. Postgres 11 was EOL'd in November 2023. Added a new version check that will prevent Chainlink from running on EOL'd Postgres. If you are running Postgres <= 11 you should upgrade to the latest version. The check can be forcibly overridden by setting SKIP_PG_VERSION_CHECK=true. -## 2.9.0 - UNRELEASED + + +## 2.9.0 - 2024-02-22 ### Added @@ -54,8 +56,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ServerPubKey = '...' ``` - - ## 2.8.0 - 2024-01-24 ### Added From bf64c293f99866eb8a92de1cc776b3c4ca966e0e Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 27 Feb 2024 20:57:08 +0000 Subject: [PATCH 16/20] Bump chainlink-common (#12195) * Bump chainlink-common * bump again --------- Co-authored-by: Bolek Kulbabinski <1416262+bolekk@users.noreply.github.com> --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 5039897bec8..b389d30f4ac 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -20,7 +20,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 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-20240215150045-fe2ba71b2f0a diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 066bc9592a5..f90d2aade47 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1173,8 +1173,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 h1:5aer8Pkw3XlXLjcPzWozy3RAbYQjVjpruxDeQENcVMw= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/go.mod b/go.mod index 6dab12267db..b01750a139a 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ require ( github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 diff --git a/go.sum b/go.sum index e04289334ee..5e386c5b0de 100644 --- a/go.sum +++ b/go.sum @@ -1168,8 +1168,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 h1:5aer8Pkw3XlXLjcPzWozy3RAbYQjVjpruxDeQENcVMw= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index caec4f79373..a44980cc265 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 github.com/smartcontractkit/chainlink-testing-framework v1.24.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0340d6b31ac..8c69edc0892 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1507,8 +1507,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 h1:5aer8Pkw3XlXLjcPzWozy3RAbYQjVjpruxDeQENcVMw= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index ab78012d982..c5aba2776c0 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -15,7 +15,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 github.com/smartcontractkit/chainlink-testing-framework v1.24.1 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index a6517124c67..f1566970ac0 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1490,8 +1490,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.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.20240227153854-c56d79341a8e h1:3fA2bobIvvfB7Ia8XQhpJRAXlm+Fbw7NZaCw4GaclIk= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227153854-c56d79341a8e/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61 h1:5aer8Pkw3XlXLjcPzWozy3RAbYQjVjpruxDeQENcVMw= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240227191958-d13aad8b4d61/go.mod h1:6aXWSEQawX2oZXcPPOdxnEGufAhj7PqPKolXf6ijRGA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= From e37f7e2d1a1859a0853ad6ecfbe3c339c02d2248 Mon Sep 17 00:00:00 2001 From: Jim W Date: Tue, 27 Feb 2024 17:51:56 -0500 Subject: [PATCH 17/20] alias github.com/pkg/errors to pkgerrors (#11848) * rename some pkgerror pkgs * rename pkgerrors in evm codebase * fix bad import * run go mod tidy * rename more pkgs * cleanup * fix linting issues * fix merge bugs * revert all changes to the core/cmd dir * revert all changes to core/services/relay/evm * fix merge errors --- .../chainlink-cluster/dashboard/dashboard.go | 6 +- core/auth/auth.go | 7 ++- core/bridges/external_initiator.go | 6 +- core/bridges/orm.go | 26 ++++----- core/cbor/cbor.go | 4 +- core/chains/evm/assets/wei.go | 12 ++-- core/chains/evm/client/client.go | 4 +- core/chains/evm/client/client_test.go | 4 +- core/chains/evm/client/erroring_node.go | 52 ++++++++--------- core/chains/evm/client/errors.go | 26 ++++----- core/chains/evm/client/errors_test.go | 6 +- core/chains/evm/client/helpers_test.go | 10 ++-- core/chains/evm/client/node.go | 26 ++++----- core/chains/evm/client/node_lifecycle.go | 6 +- core/chains/evm/client/pool.go | 8 +-- core/chains/evm/client/rpc_client.go | 16 +++--- .../evm/forwarders/forwarder_manager.go | 18 +++--- core/chains/evm/forwarders/orm.go | 10 ++-- core/chains/evm/gas/arbitrum_estimator.go | 12 ++-- .../chains/evm/gas/arbitrum_estimator_test.go | 4 +- .../chains/evm/gas/block_history_estimator.go | 56 +++++++++---------- .../evm/gas/block_history_estimator_test.go | 20 +++---- core/chains/evm/gas/fixed_price_estimator.go | 4 +- core/chains/evm/gas/models.go | 22 ++++---- core/chains/evm/gas/models_test.go | 12 ++-- .../evm/gas/suggested_price_estimator.go | 22 ++++---- .../evm/gas/suggested_price_estimator_test.go | 8 +-- .../evm/headtracker/head_listener_test.go | 4 +- core/chains/evm/headtracker/orm.go | 12 ++-- core/chains/evm/log/broadcaster.go | 8 +-- core/chains/evm/log/orm.go | 26 ++++----- core/chains/evm/log/registrations.go | 14 ++--- core/chains/evm/logpoller/disabled.go | 4 +- core/chains/evm/logpoller/helper_test.go | 4 +- core/chains/evm/logpoller/log_poller.go | 56 +++++++++---------- .../evm/logpoller/log_poller_internal_test.go | 6 +- core/chains/evm/logpoller/orm.go | 10 ++-- core/chains/evm/logpoller/orm_test.go | 14 ++--- core/chains/evm/monitor/balance.go | 4 +- core/chains/evm/monitor/balance_test.go | 4 +- core/chains/evm/txmgr/attempts.go | 40 ++++++------- core/chains/evm/txmgr/attempts_test.go | 6 +- core/chains/evm/txmgr/common.go | 4 +- core/chains/evm/txmgr/nonce_syncer.go | 8 +-- core/chains/evm/txmgr/nonce_syncer_test.go | 4 +- core/chains/evm/txmgr/resender_test.go | 4 +- core/chains/evm/txmgr/transmitchecker.go | 26 ++++----- core/chains/evm/txmgr/transmitchecker_test.go | 14 ++--- .../evm/types/internal/blocks/transactions.go | 4 +- core/chains/evm/types/models.go | 14 ++--- core/chains/evm/types/models_test.go | 6 +- core/chains/evm/types/types.go | 20 +++---- core/chains/evm/utils/ethabi.go | 4 +- core/chains/evm/utils/ethabi_test.go | 4 +- core/config/app_config.go | 4 +- core/config/docs/docs_test.go | 4 +- core/config/parse/parsers.go | 4 +- core/gethwrappers/versions.go | 28 +++++----- core/internal/testutils/httptest/httptest.go | 4 +- core/internal/testutils/keystest/keystest.go | 4 +- core/logger/zap.go | 4 +- core/sessions/localauth/orm.go | 32 +++++------ core/sessions/session.go | 4 +- core/sessions/user.go | 10 ++-- core/sessions/webauthn.go | 8 +-- core/store/migrate/migrate.go | 8 +-- 66 files changed, 423 insertions(+), 422 deletions(-) diff --git a/charts/chainlink-cluster/dashboard/dashboard.go b/charts/chainlink-cluster/dashboard/dashboard.go index 19a596b63e9..54b59ae25e6 100644 --- a/charts/chainlink-cluster/dashboard/dashboard.go +++ b/charts/chainlink-cluster/dashboard/dashboard.go @@ -14,7 +14,7 @@ import ( "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" "github.com/K-Phoen/grabana/variable/query" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) /* @@ -954,10 +954,10 @@ func (m *CLClusterDashboard) Deploy(ctx context.Context) error { client := grabana.NewClient(&http.Client{}, m.GrafanaURL, grabana.WithAPIToken(m.GrafanaToken)) folder, err := client.FindOrCreateFolder(ctx, m.Folder) if err != nil { - return errors.Wrap(err, ErrFailedToCreateFolder) + return pkgerrors.Wrap(err, ErrFailedToCreateFolder) } if _, err := client.UpsertDashboard(ctx, folder, m.builder); err != nil { - return errors.Wrap(err, ErrFailedToCreateDashboard) + return pkgerrors.Wrap(err, ErrFailedToCreateDashboard) } return nil } diff --git a/core/auth/auth.go b/core/auth/auth.go index f881afab736..62f1ab528a2 100644 --- a/core/auth/auth.go +++ b/core/auth/auth.go @@ -4,9 +4,10 @@ import ( "encoding/hex" "fmt" + pkgerrors "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/pkg/errors" "golang.org/x/crypto/sha3" ) @@ -14,7 +15,7 @@ var ( // ErrorAuthFailed is a generic authentication failed - but not because of // some system failure on our behalf (i.e. HTTP 5xx), more detail is not // given - ErrorAuthFailed = errors.New("Authentication failed") + ErrorAuthFailed = pkgerrors.New("Authentication failed") ) // Token is used for API authentication. @@ -57,7 +58,7 @@ func HashedSecret(ta *Token, salt string) (string, error) { hasher := sha3.New256() _, err := hasher.Write(hashInput(ta, salt)) if err != nil { - return "", errors.Wrap(err, "error writing external initiator authentication to hasher") + return "", pkgerrors.Wrap(err, "error writing external initiator authentication to hasher") } return hex.EncodeToString(hasher.Sum(nil)), nil } diff --git a/core/bridges/external_initiator.go b/core/bridges/external_initiator.go index 53d00e77bbb..bfec3adb407 100644 --- a/core/bridges/external_initiator.go +++ b/core/bridges/external_initiator.go @@ -5,11 +5,11 @@ import ( "strings" "time" + pkgerrors "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/pkg/errors" ) // ExternalInitiatorRequest is the incoming record used to create an ExternalInitiator. @@ -42,7 +42,7 @@ func NewExternalInitiator( salt := utils.NewSecret(utils.DefaultSecretSize) hashedSecret, err := auth.HashedSecret(eia, salt) if err != nil { - return nil, errors.Wrap(err, "error hashing secret for external initiator") + return nil, pkgerrors.Wrap(err, "error hashing secret for external initiator") } return &ExternalInitiator{ diff --git a/core/bridges/orm.go b/core/bridges/orm.go index 8ae6b855c88..f4728ea0662 100644 --- a/core/bridges/orm.go +++ b/core/bridges/orm.go @@ -7,7 +7,7 @@ import ( "time" "github.com/jmoiron/sqlx" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -67,7 +67,7 @@ func (o *orm) FindBridge(name BridgeName) (bt BridgeType, err error) { // Expects all bridges to be unique func (o *orm) FindBridges(names []BridgeName) (bts []BridgeType, err error) { if len(names) == 0 { - return nil, errors.Errorf("at least one bridge name is required") + return nil, pkgerrors.Errorf("at least one bridge name is required") } var allFoundBts []BridgeType @@ -99,7 +99,7 @@ func (o *orm) FindBridges(names []BridgeName) (bts []BridgeType, err error) { } allFoundBts = append(allFoundBts, bts...) if len(allFoundBts) != len(names) { - return nil, errors.Errorf("not all bridges exist, asked for %v, exists %v", names, allFoundBts) + return nil, pkgerrors.Errorf("not all bridges exist, asked for %v, exists %v", names, allFoundBts) } return allFoundBts, nil } @@ -128,11 +128,11 @@ func (o *orm) DeleteBridgeType(bt *BridgeType) error { func (o *orm) BridgeTypes(offset int, limit int) (bridges []BridgeType, count int, err error) { err = o.q.Transaction(func(tx pg.Queryer) error { if err = tx.Get(&count, "SELECT COUNT(*) FROM bridge_types"); err != nil { - return errors.Wrap(err, "BridgeTypes failed to get count") + return pkgerrors.Wrap(err, "BridgeTypes failed to get count") } sql := `SELECT * FROM bridge_types ORDER BY name asc LIMIT $1 OFFSET $2;` if err = tx.Select(&bridges, sql, limit, offset); err != nil { - return errors.Wrap(err, "BridgeTypes failed to load bridge_types") + return pkgerrors.Wrap(err, "BridgeTypes failed to load bridge_types") } return nil }, pg.OptReadOnlyTx()) @@ -157,7 +157,7 @@ func (o *orm) CreateBridgeType(bt *BridgeType) error { o.bridgeTypesCache.Store(bt.Name, *bt) } - return errors.Wrap(err, "CreateBridgeType failed") + return pkgerrors.Wrap(err, "CreateBridgeType failed") } // UpdateBridgeType updates the bridge type. @@ -179,7 +179,7 @@ func (o *orm) GetCachedResponse(dotId string, specId int32, maxElapsed time.Dura finished_at > ($3) ORDER BY finished_at DESC LIMIT 1;` - err = errors.Wrap(o.q.Get(&response, sql, dotId, specId, stalenessThreshold), fmt.Sprintf("failed to fetch last good value for task %s spec %d", dotId, specId)) + err = pkgerrors.Wrap(o.q.Get(&response, sql, dotId, specId, stalenessThreshold), fmt.Sprintf("failed to fetch last good value for task %s spec %d", dotId, specId)) return } @@ -190,7 +190,7 @@ func (o *orm) UpsertBridgeResponse(dotId string, specId int32, response []byte) DO UPDATE SET value = $3, finished_at = $4;` err := o.q.ExecQ(sql, dotId, specId, response, time.Now()) - return errors.Wrap(err, "failed to upsert bridge response") + return pkgerrors.Wrap(err, "failed to upsert bridge response") } // --- External Initiator @@ -199,12 +199,12 @@ func (o *orm) UpsertBridgeResponse(dotId string, specId int32, response []byte) func (o *orm) ExternalInitiators(offset int, limit int) (exis []ExternalInitiator, count int, err error) { err = o.q.Transaction(func(tx pg.Queryer) error { if err = tx.Get(&count, "SELECT COUNT(*) FROM external_initiators"); err != nil { - return errors.Wrap(err, "ExternalInitiators failed to get count") + return pkgerrors.Wrap(err, "ExternalInitiators failed to get count") } sql := `SELECT * FROM external_initiators ORDER BY name asc LIMIT $1 OFFSET $2;` if err = tx.Select(&exis, sql, limit, offset); err != nil { - return errors.Wrap(err, "ExternalInitiators failed to load external_initiators") + return pkgerrors.Wrap(err, "ExternalInitiators failed to load external_initiators") } return nil }, pg.OptReadOnlyTx()) @@ -221,12 +221,12 @@ func (o *orm) CreateExternalInitiator(externalInitiator *ExternalInitiator) (err var stmt *sqlx.NamedStmt stmt, err = tx.PrepareNamed(query) if err != nil { - return errors.Wrap(err, "failed to prepare named stmt") + return pkgerrors.Wrap(err, "failed to prepare named stmt") } defer stmt.Close() - return errors.Wrap(stmt.Get(externalInitiator, externalInitiator), "failed to load external_initiator") + return pkgerrors.Wrap(stmt.Get(externalInitiator, externalInitiator), "failed to load external_initiator") }) - return errors.Wrap(err, "CreateExternalInitiator failed") + return pkgerrors.Wrap(err, "CreateExternalInitiator failed") } // DeleteExternalInitiator removes an external initiator diff --git a/core/cbor/cbor.go b/core/cbor/cbor.go index cc3f74e423e..fb6e6c88f95 100644 --- a/core/cbor/cbor.go +++ b/core/cbor/cbor.go @@ -6,7 +6,7 @@ import ( "math/big" "github.com/fxamacker/cbor/v2" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) // ParseDietCBOR attempts to coerce the input byte array into valid CBOR. @@ -28,7 +28,7 @@ func ParseDietCBOR(b []byte) (map[string]interface{}, error) { output, ok := coerced.(map[string]interface{}) if !ok { - return nil, errors.New("cbor data cannot be coerced to map") + return nil, pkgerrors.New("cbor data cannot be coerced to map") } return output, nil diff --git a/core/chains/evm/assets/wei.go b/core/chains/evm/assets/wei.go index 8bacabfdb4a..3621e4492a4 100644 --- a/core/chains/evm/assets/wei.go +++ b/core/chains/evm/assets/wei.go @@ -6,7 +6,7 @@ import ( "math/big" "strings" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/shopspring/decimal" "golang.org/x/exp/constraints" @@ -185,7 +185,7 @@ func (w *Wei) UnmarshalText(b []byte) error { t = strings.TrimSuffix(t, " ") d, err := decimal.NewFromString(t) if err != nil { - return errors.Wrapf(err, "unable to parse %q", s) + return pkgerrors.Wrapf(err, "unable to parse %q", s) } se := suffixExp(suf) if d.IsInteger() { @@ -196,8 +196,8 @@ func (w *Wei) UnmarshalText(b []byte) error { d = d.Mul(decimal.New(1, se)) if !d.IsInteger() { - err := errors.New("maximum precision is wei") - return errors.Wrapf(err, "unable to parse %q", s) + err := pkgerrors.New("maximum precision is wei") + return pkgerrors.Wrapf(err, "unable to parse %q", s) } *w = (Wei)(*d.BigInt()) return nil @@ -206,13 +206,13 @@ func (w *Wei) UnmarshalText(b []byte) error { // unrecognized or missing suffix d, err := decimal.NewFromString(s) if err != nil { - return errors.Wrapf(err, "unable to parse %q", s) + return pkgerrors.Wrapf(err, "unable to parse %q", s) } if d.IsInteger() { *w = (Wei)(*d.BigInt()) return nil } - return errors.Errorf("unable to parse %q", s) + return pkgerrors.Errorf("unable to parse %q", s) } func (w *Wei) ToInt() *big.Int { diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index e2ae8c26403..70d989ae808 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) const queryTimeout = 10 * time.Second @@ -126,7 +126,7 @@ func NewClientWithNodes(lggr logger.Logger, selectionMode string, leaseDuration // node's remote chain ID matches the local one func (client *client) Dial(ctx context.Context) error { if err := client.pool.Dial(ctx); err != nil { - return errors.Wrap(err, "failed to dial pool") + return pkgerrors.Wrap(err, "failed to dial pool") } return nil } diff --git a/core/chains/evm/client/client_test.go b/core/chains/evm/client/client_test.go index 281b8bf4227..62acf146e48 100644 --- a/core/chains/evm/client/client_test.go +++ b/core/chains/evm/client/client_test.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" @@ -145,7 +145,7 @@ func TestEthClient_TransactionReceipt(t *testing.T) { hash := common.HexToHash(txHash) _, err = ethClient.TransactionReceipt(testutils.Context(t), hash) - require.Equal(t, ethereum.NotFound, errors.Cause(err)) + require.Equal(t, ethereum.NotFound, pkgerrors.Cause(err)) } }) } diff --git a/core/chains/evm/client/erroring_node.go b/core/chains/evm/client/erroring_node.go index 059f76d608a..00e8465bca3 100644 --- a/core/chains/evm/client/erroring_node.go +++ b/core/chains/evm/client/erroring_node.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) var _ Node = (*erroringNode)(nil) @@ -27,104 +27,104 @@ func (e *erroringNode) SubscribersCount() int32 { func (e *erroringNode) ChainID() (chainID *big.Int) { return nil } -func (e *erroringNode) Start(ctx context.Context) error { return errors.New(e.errMsg) } +func (e *erroringNode) Start(ctx context.Context) error { return pkgerrors.New(e.errMsg) } func (e *erroringNode) Close() error { return nil } func (e *erroringNode) Verify(ctx context.Context, expectedChainID *big.Int) (err error) { - return errors.New(e.errMsg) + return pkgerrors.New(e.errMsg) } func (e *erroringNode) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { - return errors.New(e.errMsg) + return pkgerrors.New(e.errMsg) } func (e *erroringNode) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { - return errors.New(e.errMsg) + return pkgerrors.New(e.errMsg) } func (e *erroringNode) SendTransaction(ctx context.Context, tx *types.Transaction) error { - return errors.New(e.errMsg) + return pkgerrors.New(e.errMsg) } func (e *erroringNode) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { - return 0, errors.New(e.errMsg) + return 0, pkgerrors.New(e.errMsg) } func (e *erroringNode) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { - return 0, errors.New(e.errMsg) + return 0, pkgerrors.New(e.errMsg) } func (e *erroringNode) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) BlockNumber(ctx context.Context) (uint64, error) { - return 0, errors.New(e.errMsg) + return 0, pkgerrors.New(e.errMsg) } func (e *erroringNode) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { - return 0, errors.New(e.errMsg) + return 0, pkgerrors.New(e.errMsg) } func (e *erroringNode) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) HeaderByNumber(_ context.Context, _ *big.Int) (*types.Header, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) HeaderByHash(_ context.Context, _ common.Hash) (*types.Header, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, args ...interface{}) (ethereum.Subscription, error) { - return nil, errors.New(e.errMsg) + return nil, pkgerrors.New(e.errMsg) } func (e *erroringNode) String() string { diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 1c470f0cfc6..42a983b40d7 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -36,7 +36,7 @@ func (s *SendError) Fatal() bool { // CauseStr returns the string of the original error func (s *SendError) CauseStr() string { if s.err != nil { - return errors.Cause(s.err).Error() + return pkgerrors.Cause(s.err).Error() } return "" } @@ -316,7 +316,7 @@ func (s *SendError) IsTimeout() bool { if s.err == nil { return false } - return errors.Is(s.err, context.DeadlineExceeded) + return pkgerrors.Is(s.err, context.DeadlineExceeded) } // IsCanceled indicates if the error was caused by an context cancellation @@ -327,18 +327,18 @@ func (s *SendError) IsCanceled() bool { if s.err == nil { return false } - return errors.Is(s.err, context.Canceled) + return pkgerrors.Is(s.err, context.Canceled) } func NewFatalSendError(e error) *SendError { if e == nil { return nil } - return &SendError{err: errors.WithStack(e), fatal: true} + return &SendError{err: pkgerrors.WithStack(e), fatal: true} } func NewSendErrorS(s string) *SendError { - return NewSendError(errors.New(s)) + return NewSendError(pkgerrors.New(s)) } func NewSendError(e error) *SendError { @@ -346,7 +346,7 @@ func NewSendError(e error) *SendError { return nil } fatal := isFatalSendError(e) - return &SendError{err: errors.WithStack(e), fatal: fatal} + return &SendError{err: pkgerrors.WithStack(e), fatal: fatal} } // Geth/parity returns these errors if the transaction failed in such a way that: @@ -356,7 +356,7 @@ func isFatalSendError(err error) bool { if err == nil { return false } - str := errors.Cause(err).Error() + str := pkgerrors.Cause(err).Error() for _, client := range clients { if _, ok := client[Fatal]; !ok { continue @@ -414,20 +414,20 @@ func ExtractRPCErrorOrNil(err error) *JsonError { // { "error": { "code": 3, "data": "0xABC123...", "message": "execution reverted: hello world" } } // revert reason automatically parsed if a simple require and included in message. func ExtractRPCError(baseErr error) (*JsonError, error) { if baseErr == nil { - return nil, errors.New("no error present") + return nil, pkgerrors.New("no error present") } - cause := errors.Cause(baseErr) + cause := pkgerrors.Cause(baseErr) jsonBytes, err := json.Marshal(cause) if err != nil { - return nil, errors.Wrap(err, "unable to marshal err to json") + return nil, pkgerrors.Wrap(err, "unable to marshal err to json") } jErr := JsonError{} err = json.Unmarshal(jsonBytes, &jErr) if err != nil { - return nil, errors.Wrapf(err, "unable to unmarshal json into jsonError struct (got: %v)", baseErr) + return nil, pkgerrors.Wrapf(err, "unable to unmarshal json into jsonError struct (got: %v)", baseErr) } if jErr.Code == 0 { - return nil, errors.Errorf("not a RPCError because it does not have a code (got: %v)", baseErr) + return nil, pkgerrors.Errorf("not a RPCError because it does not have a code (got: %v)", baseErr) } return &jErr, nil } diff --git a/core/chains/evm/client/errors_test.go b/core/chains/evm/client/errors_test.go index f47b93c0400..e6ba89fcb5a 100644 --- a/core/chains/evm/client/errors_test.go +++ b/core/chains/evm/client/errors_test.go @@ -3,14 +3,14 @@ package client_test import ( "testing" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" ) func newSendErrorWrapped(s string) *evmclient.SendError { - return evmclient.NewSendError(errors.Wrap(errors.New(s), "wrapped with some old bollocks")) + return evmclient.NewSendError(pkgerrors.Wrap(pkgerrors.New(s), "wrapped with some old bollocks")) } type errorCase struct { @@ -362,7 +362,7 @@ func Test_Eth_Errors_Fatal(t *testing.T) { for _, test := range tests { t.Run(test.message, func(t *testing.T) { - err := evmclient.NewSendError(errors.New(test.message)) + err := evmclient.NewSendError(pkgerrors.New(test.message)) assert.Equal(t, test.expect, err.Fatal()) }) } diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index c1652c19c26..e400d95bef4 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -45,7 +45,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads } if parsed.Scheme != "ws" && parsed.Scheme != "wss" { - return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) + return nil, pkgerrors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } lggr := logger.Sugared(logger.Test(t)) @@ -56,7 +56,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads var sendonlys []SendOnlyNode for i, url := range sendonlyRPCURLs { if url.Scheme != "http" && url.Scheme != "https" { - return nil, errors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", url.String()) + return nil, pkgerrors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", url.String()) } s := NewSendOnlyNode(lggr, url, fmt.Sprintf("eth-sendonly-%d", i), chainID) sendonlys = append(sendonlys, s) @@ -89,7 +89,7 @@ func NewChainClientWithTestNode( } if parsed.Scheme != "ws" && parsed.Scheme != "wss" { - return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) + return nil, pkgerrors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } lggr := logger.Test(t) @@ -102,7 +102,7 @@ func NewChainClientWithTestNode( var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient] for i, u := range sendonlyRPCURLs { if u.Scheme != "http" && u.Scheme != "https" { - return nil, errors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String()) + return nil, pkgerrors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String()) } var empty url.URL rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, commonclient.Secondary) diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index aa472d605a6..474ff2700b4 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/google/uuid" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -245,7 +245,7 @@ func (n *node) start(startCtx context.Context) { verifyCtx, verifyCancel := n.makeQueryCtx(startCtx) defer verifyCancel() - if err := n.verify(verifyCtx); errors.Is(err, errInvalidChainID) { + if err := n.verify(verifyCtx); pkgerrors.Is(err, errInvalidChainID) { n.lfcLog.Errorw("Verify failed: EVM Node has the wrong chain ID", "err", err) n.declareInvalidChainID() return @@ -274,7 +274,7 @@ func (n *node) dial(callerCtx context.Context) error { wsrpc, err := rpc.DialWebsocket(ctx, n.ws.uri.String(), "") if err != nil { promEVMPoolRPCNodeDialsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() - return errors.Wrapf(err, "error while dialing websocket: %v", n.ws.uri.Redacted()) + return pkgerrors.Wrapf(err, "error while dialing websocket: %v", n.ws.uri.Redacted()) } var httprpc *rpc.Client @@ -282,7 +282,7 @@ func (n *node) dial(callerCtx context.Context) error { httprpc, err = rpc.DialHTTP(n.http.uri.String()) if err != nil { promEVMPoolRPCNodeDialsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() - return errors.Wrapf(err, "error while dialing HTTP: %v", n.http.uri.Redacted()) + return pkgerrors.Wrapf(err, "error while dialing HTTP: %v", n.http.uri.Redacted()) } } @@ -299,7 +299,7 @@ func (n *node) dial(callerCtx context.Context) error { return nil } -var errInvalidChainID = errors.New("invalid chain id") +var errInvalidChainID = pkgerrors.New("invalid chain id") // verify checks that all connections to eth nodes match the given chain ID // Not thread-safe @@ -323,10 +323,10 @@ func (n *node) verify(callerCtx context.Context) (err error) { var chainID *big.Int if chainID, err = n.ws.geth.ChainID(ctx); err != nil { promFailed() - return errors.Wrapf(err, "failed to verify chain ID for node %s", n.name) + return pkgerrors.Wrapf(err, "failed to verify chain ID for node %s", n.name) } else if chainID.Cmp(n.chainID) != 0 { promFailed() - return errors.Wrapf( + return pkgerrors.Wrapf( errInvalidChainID, "websocket rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", chainID.String(), @@ -337,10 +337,10 @@ func (n *node) verify(callerCtx context.Context) (err error) { if n.http != nil { if chainID, err = n.http.geth.ChainID(ctx); err != nil { promFailed() - return errors.Wrapf(err, "failed to verify chain ID for node %s", n.name) + return pkgerrors.Wrapf(err, "failed to verify chain ID for node %s", n.name) } else if chainID.Cmp(n.chainID) != 0 { promFailed() - return errors.Wrapf( + return pkgerrors.Wrapf( errInvalidChainID, "http rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", chainID.String(), @@ -1094,10 +1094,10 @@ func wrap(err error, tp string) error { if err == nil { return nil } - if errors.Cause(err).Error() == "context deadline exceeded" { - err = errors.Wrap(err, "remote eth node timed out") + if pkgerrors.Cause(err).Error() == "context deadline exceeded" { + err = pkgerrors.Wrap(err, "remote eth node timed out") } - return errors.Wrapf(err, "%s call failed", tp) + return pkgerrors.Wrapf(err, "%s call failed", tp) } // makeLiveQueryCtxAndSafeGetClients wraps makeQueryCtx but returns error if node is not NodeStateAlive. @@ -1106,7 +1106,7 @@ func (n *node) makeLiveQueryCtxAndSafeGetClients(parentCtx context.Context) (ctx // context n.stateMu.RLock() if n.state != NodeStateAlive { - err = errors.Errorf("cannot execute RPC call on node with state: %s", n.state) + err = pkgerrors.Errorf("cannot execute RPC call on node with state: %s", n.state) n.stateMu.RUnlock() return } diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index f2232a14935..41add532222 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -7,7 +7,7 @@ import ( "math/big" "time" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -381,7 +381,7 @@ func (n *node) unreachableLoop() { err = n.verify(n.nodeCtx) - if errors.Is(err, errInvalidChainID) { + if pkgerrors.Is(err, errInvalidChainID) { lggr.Errorw("Failed to redial RPC node; remote endpoint returned the wrong chain ID", "err", err) n.declareInvalidChainID() return @@ -426,7 +426,7 @@ func (n *node) invalidChainIDLoop() { return case <-time.After(chainIDRecheckBackoff.Duration()): err := n.verify(n.nodeCtx) - if errors.Is(err, errInvalidChainID) { + if pkgerrors.Is(err, errInvalidChainID) { lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err) continue } else if err != nil { diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 3c33b3dbd0a..891fd8c9226 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -133,12 +133,12 @@ func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Durati func (p *Pool) Dial(ctx context.Context) error { return p.StartOnce("Pool", func() (merr error) { if len(p.nodes) == 0 { - return errors.Errorf("no available nodes for chain %s", p.chainID.String()) + return pkgerrors.Errorf("no available nodes for chain %s", p.chainID.String()) } var ms services.MultiStart for _, n := range p.nodes { if n.ChainID().Cmp(p.chainID) != 0 { - return ms.CloseBecause(errors.Errorf("node %s has chain ID %s which does not match pool chain ID of %s", n.String(), n.ChainID().String(), p.chainID.String())) + return ms.CloseBecause(pkgerrors.Errorf("node %s has chain ID %s which does not match pool chain ID of %s", n.String(), n.ChainID().String(), p.chainID.String())) } rawNode, ok := n.(*node) if ok { @@ -155,7 +155,7 @@ func (p *Pool) Dial(ctx context.Context) error { } for _, s := range p.sendonlys { if s.ChainID().Cmp(p.chainID) != 0 { - return ms.CloseBecause(errors.Errorf("sendonly node %s has chain ID %s which does not match pool chain ID of %s", s.String(), s.ChainID().String(), p.chainID.String())) + return ms.CloseBecause(pkgerrors.Errorf("sendonly node %s has chain ID %s which does not match pool chain ID of %s", s.String(), s.ChainID().String(), p.chainID.String())) } if err := ms.Start(ctx, s); err != nil { return err diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index d71762ac09a..38d6a123f49 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/google/uuid" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -130,7 +130,7 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { wsrpc, err := rpc.DialWebsocket(ctx, r.ws.uri.String(), "") if err != nil { promEVMPoolRPCNodeDialsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() - return errors.Wrapf(err, "error while dialing websocket: %v", r.ws.uri.Redacted()) + return pkgerrors.Wrapf(err, "error while dialing websocket: %v", r.ws.uri.Redacted()) } r.ws.rpc = wsrpc @@ -159,7 +159,7 @@ func (r *rpcClient) DialHTTP() error { httprpc, err := rpc.DialHTTP(r.http.uri.String()) if err != nil { promEVMPoolRPCNodeDialsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() - return errors.Wrapf(err, "error while dialing HTTP: %v", r.http.uri.Redacted()) + return pkgerrors.Wrapf(err, "error while dialing HTTP: %v", r.http.uri.Redacted()) } r.http.rpc = httprpc @@ -582,7 +582,7 @@ func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) func (r *rpcClient) SimulateTransaction(ctx context.Context, tx *types.Transaction) error { // Not Implemented - return errors.New("SimulateTransaction not implemented") + return pkgerrors.New("SimulateTransaction not implemented") } func (r *rpcClient) SendEmptyTransaction( @@ -594,7 +594,7 @@ func (r *rpcClient) SendEmptyTransaction( fromAddress common.Address, ) (txhash string, err error) { // Not Implemented - return "", errors.New("SendEmptyTransaction not implemented") + return "", pkgerrors.New("SendEmptyTransaction not implemented") } // PendingSequenceAt returns one higher than the highest nonce from both mempool and mined transactions @@ -1067,10 +1067,10 @@ func wrapCallError(err error, tp string) error { if err == nil { return nil } - if errors.Cause(err).Error() == "context deadline exceeded" { - err = errors.Wrap(err, "remote node timed out") + if pkgerrors.Cause(err).Error() == "context deadline exceeded" { + err = pkgerrors.Wrap(err, "remote node timed out") } - return errors.Wrapf(err, "%s call failed", tp) + return pkgerrors.Wrapf(err, "%s call failed", tp) } func (r *rpcClient) wrapWS(err error) error { diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index cabedf79aee..452bb87cae2 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -8,7 +8,7 @@ import ( "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" + pkgerrors "github.com/pkg/errors" "github.com/jmoiron/sqlx" @@ -82,7 +82,7 @@ func (f *FwdMgr) Start(ctx context.Context) error { fwdrs, err := f.ORM.FindForwardersByChain(big.Big(*chainId)) if err != nil { - return errors.Wrapf(err, "Failed to retrieve forwarders for chain %d", chainId) + return pkgerrors.Wrapf(err, "Failed to retrieve forwarders for chain %d", chainId) } if len(fwdrs) != 0 { f.initForwardersCache(ctx, fwdrs) @@ -93,12 +93,12 @@ func (f *FwdMgr) Start(ctx context.Context) error { f.authRcvr, err = authorized_receiver.NewAuthorizedReceiver(common.Address{}, f.evmClient) if err != nil { - return errors.Wrap(err, "Failed to init AuthorizedReceiver") + return pkgerrors.Wrap(err, "Failed to init AuthorizedReceiver") } f.offchainAgg, err = offchain_aggregator_wrapper.NewOffchainAggregator(common.Address{}, f.evmClient) if err != nil { - return errors.Wrap(err, "Failed to init OffchainAggregator") + return pkgerrors.Wrap(err, "Failed to init OffchainAggregator") } f.wg.Add(1) @@ -130,7 +130,7 @@ func (f *FwdMgr) ForwarderFor(addr common.Address) (forwarder common.Address, er } } } - return common.Address{}, errors.Errorf("Cannot find forwarder for given EOA") + return common.Address{}, pkgerrors.Errorf("Cannot find forwarder for given EOA") } func (f *FwdMgr) ConvertPayload(dest common.Address, origPayload []byte) ([]byte, error) { @@ -148,7 +148,7 @@ func (f *FwdMgr) ConvertPayload(dest common.Address, origPayload []byte) ([]byte func (f *FwdMgr) getForwardedPayload(dest common.Address, origPayload []byte) ([]byte, error) { callArgs, err := forwardABI.Inputs.Pack(dest, origPayload) if err != nil { - return nil, errors.Wrap(err, "Failed to pack forwarder payload") + return nil, pkgerrors.Wrap(err, "Failed to pack forwarder payload") } dataBytes := append(forwardABI.ID, callArgs...) @@ -161,7 +161,7 @@ func (f *FwdMgr) getContractSenders(addr common.Address) ([]common.Address, erro } senders, err := f.getAuthorizedSenders(f.ctx, addr) if err != nil { - return nil, errors.Wrapf(err, "Failed to call getAuthorizedSenders on %s", addr) + return nil, pkgerrors.Wrapf(err, "Failed to call getAuthorizedSenders on %s", addr) } f.setCachedSenders(addr, senders) if err = f.subscribeSendersChangedLogs(addr); err != nil { @@ -173,7 +173,7 @@ func (f *FwdMgr) getContractSenders(addr common.Address) ([]common.Address, erro func (f *FwdMgr) getAuthorizedSenders(ctx context.Context, addr common.Address) ([]common.Address, error) { c, err := authorized_receiver.NewAuthorizedReceiverCaller(addr, f.evmClient) if err != nil { - return nil, errors.Wrap(err, "Failed to init forwarder caller") + return nil, pkgerrors.Wrap(err, "Failed to init forwarder caller") } opts := bind.CallOpts{Context: ctx, Pending: false} senders, err := c.GetAuthorizedSenders(&opts) @@ -296,7 +296,7 @@ func (f *FwdMgr) handleAuthChange(log evmlogpoller.Log) error { if ethLog.Topics[0] == authChangedTopic { event, err := f.authRcvr.ParseAuthorizedSendersChanged(ethLog) if err != nil { - return errors.New("Failed to parse senders change log") + return pkgerrors.New("Failed to parse senders change log") } f.setCachedSenders(event.Raw.Address, event.Senders) } diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index 2a455360190..8b4ba5273a3 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -5,7 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -64,7 +64,7 @@ func (o *orm) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainID i // If the forwarder wasn't found, we still want to delete the filter. // In that case, the transaction must return nil, even though DeleteForwarder // will return sql.ErrNoRows - if err2 != nil && !errors.Is(err2, sql.ErrNoRows) { + if err2 != nil && !pkgerrors.Is(err2, sql.ErrNoRows) { return err2 } rowsAffected, err2 = result.RowsAffected() @@ -116,19 +116,19 @@ func (o *orm) FindForwardersInListByChain(evmChainId big.Big, addrs []common.Add ) if err != nil { - return nil, errors.Wrap(err, "Failed to format query") + return nil, pkgerrors.Wrap(err, "Failed to format query") } query, args, err = sqlx.In(query, args...) if err != nil { - return nil, errors.Wrap(err, "Failed to run sqlx.IN on query") + return nil, pkgerrors.Wrap(err, "Failed to run sqlx.IN on query") } query = o.q.Rebind(query) err = o.q.Select(&fwdrs, query, args...) if err != nil { - return nil, errors.Wrap(err, "Failed to execute query") + return nil, pkgerrors.Wrap(err, "Failed to execute query") } return fwdrs, nil diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index a94fddc0e9d..525d439e3e4 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -76,7 +76,7 @@ func (a *arbitrumEstimator) Name() string { func (a *arbitrumEstimator) Start(ctx context.Context) error { return a.StartOnce("ArbitrumEstimator", func() error { if err := a.EvmEstimator.Start(ctx); err != nil { - return errors.Wrap(err, "failed to start gas price estimator") + return pkgerrors.Wrap(err, "failed to start gas price estimator") } go a.run() <-a.chInitialised @@ -86,7 +86,7 @@ func (a *arbitrumEstimator) Start(ctx context.Context) error { func (a *arbitrumEstimator) Close() error { return a.StopOnce("ArbitrumEstimator", func() (err error) { close(a.chStop) - err = errors.Wrap(a.EvmEstimator.Close(), "failed to stop gas price estimator") + err = pkgerrors.Wrap(a.EvmEstimator.Close(), "failed to stop gas price estimator") <-a.chDone return }) @@ -117,7 +117,7 @@ func (a *arbitrumEstimator) GetLegacyGas(ctx context.Context, calldata []byte, l select { case a.chForceRefetch <- ch: case <-a.chStop: - err = errors.New("estimator stopped") + err = pkgerrors.New("estimator stopped") return case <-ctx.Done(): err = ctx.Err() @@ -126,7 +126,7 @@ func (a *arbitrumEstimator) GetLegacyGas(ctx context.Context, calldata []byte, l select { case <-ch: case <-a.chStop: - err = errors.New("estimator stopped") + err = pkgerrors.New("estimator stopped") return case <-ctx.Done(): err = ctx.Err() @@ -139,7 +139,7 @@ func (a *arbitrumEstimator) GetLegacyGas(ctx context.Context, calldata []byte, l "perL1CalldataUnit", perL1CalldataUnit, "chainSpecificGasLimit", chainSpecificGasLimit) }) if !ok { - return nil, 0, errors.New("estimator is not started") + return nil, 0, pkgerrors.New("estimator is not started") } else if err != nil { return } diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index dad48b528bb..e5a5af8d4f8 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -149,7 +149,7 @@ func TestArbitrumEstimator(t *testing.T) { ethClient := mocks.NewETHClient(t) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, client, ethClient) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) + client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index c8eee2f1bd0..66f3e5d2e67 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -204,7 +204,7 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { 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()) } if b.bhConfig.BlockHistorySize() == 0 { - return errors.New("BlockHistorySize must be set to a value greater than 0") + return pkgerrors.New("BlockHistorySize must be set to a value greater than 0") } fetchCtx, cancel := context.WithTimeout(ctx, MaxStartTime) @@ -222,7 +222,7 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { // NOTE: This only checks the start context, not the fetch context if ctx.Err() != nil { - return errors.Wrap(ctx.Err(), "failed to start BlockHistoryEstimator due to main context error") + return pkgerrors.Wrap(ctx.Err(), "failed to start BlockHistoryEstimator due to main context error") } b.wg.Add(1) @@ -253,11 +253,11 @@ func (b *BlockHistoryEstimator) GetLegacyGas(_ context.Context, _ []byte, gasLim gasPrice = b.getGasPrice() }) if !ok { - return nil, 0, errors.New("BlockHistoryEstimator is not started; cannot estimate gas") + return nil, 0, pkgerrors.New("BlockHistoryEstimator is not started; cannot estimate gas") } if gasPrice == nil { if !b.initialFetch.Load() { - return nil, 0, errors.New("BlockHistoryEstimator has not finished the first gas estimation yet, likely because a failure on start") + return nil, 0, pkgerrors.New("BlockHistoryEstimator has not finished the first gas estimation yet, likely because a failure on start") } b.logger.Warnw("Failed to estimate gas price. This is likely because there aren't any valid transactions to estimate from."+ "Using Evm.GasEstimator.PriceDefault as fallback.", "blocks", b.getBlockHistoryNumbers()) @@ -290,7 +290,7 @@ func (b *BlockHistoryEstimator) getTipCap() *assets.Wei { func (b *BlockHistoryEstimator) BumpLegacyGas(_ context.Context, originalGasPrice *assets.Wei, gasLimit uint32, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumpedGasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { - if errors.Is(err, commonfee.ErrConnectivity) { + if pkgerrors.Is(err, commonfee.ErrConnectivity) { b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "legacy").Inc() @@ -323,7 +323,7 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er if attempt.BroadcastBeforeBlockNum == nil { // this shouldn't happen; any broadcast attempt ought to have a // BroadcastBeforeBlockNum otherwise its an assumption violation - return errors.Errorf("BroadcastBeforeBlockNum was unexpectedly nil for attempt %s", attempt.TxHash) + return pkgerrors.Errorf("BroadcastBeforeBlockNum was unexpectedly nil for attempt %s", attempt.TxHash) } broadcastBeforeBlockNum := *attempt.BroadcastBeforeBlockNum blocksSinceBroadcast := *latestBlockNum - broadcastBeforeBlockNum @@ -352,11 +352,11 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er case 0x2: eip1559 = true default: - return errors.Errorf("attempt %s has unknown transaction type 0x%d", attempt.TxHash, attempt.TxType) + return pkgerrors.Errorf("attempt %s has unknown transaction type 0x%d", attempt.TxHash, attempt.TxType) } gasPrice, tipCap, err := b.calculatePercentilePrices(blocks, percentile, eip1559, nil, nil) if err != nil { - if errors.Is(err, ErrNoSuitableTransactions) { + if pkgerrors.Is(err, ErrNoSuitableTransactions) { b.logger.Warnf("no suitable transactions found to verify if transaction %s has been included within expected inclusion blocks of %d", attempt.TxHash, expectInclusionWithinBlocks) return nil } @@ -365,7 +365,7 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er } if !eip1559 { if attempt.GasPrice.Cmp(gasPrice) > 0 { - return errors.Wrapf(commonfee.ErrConnectivity, "transaction %s has gas price of %s, which is above percentile=%d%% (percentile price: %s) for blocks %d thru %d (checking %d blocks)", attempt.TxHash, attempt.GasPrice, percentile, gasPrice, blockHistory[l-1].Number, blockHistory[0].Number, expectInclusionWithinBlocks) + return pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction %s has gas price of %s, which is above percentile=%d%% (percentile price: %s) for blocks %d thru %d (checking %d blocks)", attempt.TxHash, attempt.GasPrice, percentile, gasPrice, blockHistory[l-1].Number, blockHistory[0].Number, expectInclusionWithinBlocks) } continue } @@ -382,7 +382,7 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er } } if sufficientFeeCap && attempt.DynamicFee.TipCap.Cmp(tipCap) > 0 { - return errors.Wrapf(commonfee.ErrConnectivity, "transaction %s has tip cap of %s, which is above percentile=%d%% (percentile tip cap: %s) for blocks %d thru %d (checking %d blocks)", attempt.TxHash, attempt.DynamicFee.TipCap, percentile, tipCap, blockHistory[l-1].Number, blockHistory[0].Number, expectInclusionWithinBlocks) + return pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction %s has tip cap of %s, which is above percentile=%d%% (percentile tip cap: %s) for blocks %d thru %d (checking %d blocks)", attempt.TxHash, attempt.DynamicFee.TipCap, percentile, tipCap, blockHistory[l-1].Number, blockHistory[0].Number, expectInclusionWithinBlocks) } } return nil @@ -390,7 +390,7 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, gasLimit uint32, maxGasPriceWei *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint32, err error) { if !b.eConfig.EIP1559DynamicFees() { - return fee, 0, errors.New("Can't get dynamic fee, EIP1559 is disabled") + return fee, 0, pkgerrors.New("Can't get dynamic fee, EIP1559 is disabled") } var feeCap *assets.Wei @@ -405,7 +405,7 @@ func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, gasLimit uint32 tipCap = b.tipCap if tipCap == nil { if !b.initialFetch.Load() { - err = errors.New("BlockHistoryEstimator has not finished the first gas estimation yet, likely because a failure on start") + err = pkgerrors.New("BlockHistoryEstimator has not finished the first gas estimation yet, likely because a failure on start") return } b.logger.Warnw("Failed to estimate gas price. This is likely because there aren't any valid transactions to estimate from."+ @@ -426,12 +426,12 @@ func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, gasLimit uint32 // This shouldn't happen on EIP-1559 blocks, since if the tip cap // is set, Start must have succeeded and we would expect an initial // base fee to be set as well - err = errors.New("BlockHistoryEstimator: no value for latest block base fee; cannot estimate EIP-1559 base fee. Are you trying to run with EIP1559 enabled on a non-EIP1559 chain?") + err = pkgerrors.New("BlockHistoryEstimator: no value for latest block base fee; cannot estimate EIP-1559 base fee. Are you trying to run with EIP1559 enabled on a non-EIP1559 chain?") return } }) if !ok { - return fee, 0, errors.New("BlockHistoryEstimator is not started; cannot estimate gas") + return fee, 0, pkgerrors.New("BlockHistoryEstimator is not started; cannot estimate gas") } if err != nil { return fee, 0, err @@ -464,7 +464,7 @@ func calcFeeCap(latestAvailableBaseFeePerGas *assets.Wei, bufferBlocks int, tipC func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee DynamicFee, originalGasLimit uint32, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint32, err error) { if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { - if errors.Is(err, commonfee.ErrConnectivity) { + if pkgerrors.Is(err, commonfee.ErrConnectivity) { b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "eip1559").Inc() @@ -531,7 +531,7 @@ func (b *BlockHistoryEstimator) Recalculate(head *evmtypes.Head) { } }) if err != nil { - if errors.Is(err, ErrNoSuitableTransactions) { + if pkgerrors.Is(err, ErrNoSuitableTransactions) { lggr.Debug("No suitable transactions, skipping") } else { lggr.Warnw("Cannot calculate percentile prices", "err", err) @@ -586,12 +586,12 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. historySize := b.size if historySize <= 0 { - return errors.Errorf("BlockHistoryEstimator: history size must be > 0, got: %d", historySize) + return pkgerrors.Errorf("BlockHistoryEstimator: history size must be > 0, got: %d", historySize) } highestBlockToFetch := head.Number - blockDelay if highestBlockToFetch < 0 { - return errors.Errorf("BlockHistoryEstimator: cannot fetch, current block height %v is lower than EVM.RPCBlockQueryDelay=%v", head.Number, blockDelay) + return pkgerrors.Errorf("BlockHistoryEstimator: cannot fetch, current block height %v is lower than EVM.RPCBlockQueryDelay=%v", head.Number, blockDelay) } lowestBlockToFetch := head.Number - historySize - blockDelay + 1 if lowestBlockToFetch < 0 { @@ -639,7 +639,7 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. for _, req := range reqs { result, err := req.Result, req.Error if err != nil { - if errors.Is(err, evmtypes.ErrMissingBlock) { + if pkgerrors.Is(err, evmtypes.ErrMissingBlock) { num := HexToInt64(req.Args[0]) missingBlocks = append(missingBlocks, num) lggr.Debugw( @@ -655,10 +655,10 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. block, is := result.(*evmtypes.Block) if !is { - return errors.Errorf("expected result to be a %T, got %T", &evmtypes.Block{}, result) + return pkgerrors.Errorf("expected result to be a %T, got %T", &evmtypes.Block{}, result) } if block == nil { - return errors.New("invariant violation: got nil block") + return pkgerrors.New("invariant violation: got nil block") } if block.Hash == (common.Hash{}) { lggr.Warnw("Block was missing hash", "block", b, "headNum", head.Number, "blockNum", block.Number) @@ -714,26 +714,26 @@ func (b *BlockHistoryEstimator) batchFetch(ctx context.Context, reqs []rpc.Batch 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) { + if pkgerrors.Is(err, context.DeadlineExceeded) { // We ran out of time, return what we have b.logger.Warnf("Batch fetching timed out; loaded %d/%d results", i, len(reqs)) for k := i; k < len(reqs); k++ { if k < j { - reqs[k].Error = errors.Wrap(err, "request failed") + reqs[k].Error = pkgerrors.Wrap(err, "request failed") } else { - reqs[k].Error = errors.Wrap(err, "request skipped; previous request exceeded deadline") + reqs[k].Error = pkgerrors.Wrap(err, "request skipped; previous request exceeded deadline") } } return nil } else if err != nil { - return errors.Wrap(err, "BlockHistoryEstimator#fetchBlocks error fetching blocks with BatchCallContext") + return pkgerrors.Wrap(err, "BlockHistoryEstimator#fetchBlocks error fetching blocks with BatchCallContext") } } return nil } var ( - ErrNoSuitableTransactions = errors.New("no suitable transactions") + ErrNoSuitableTransactions = pkgerrors.New("no suitable transactions") ) func (b *BlockHistoryEstimator) calculatePercentilePrices(blocks []evmtypes.Block, percentile int, eip1559 bool, f func(gasPrices []*assets.Wei), f2 func(tipCaps []*assets.Wei)) (gasPrice, tipCap *assets.Wei, err error) { @@ -794,7 +794,7 @@ func (b *BlockHistoryEstimator) getPricesFromBlocks(blocks []evmtypes.Block, eip func verifyBlock(block evmtypes.Block, eip1559 bool) error { if eip1559 && block.BaseFeePerGas == nil { - return errors.New("EIP-1559 mode was enabled, but block was missing baseFeePerGas") + return pkgerrors.New("EIP-1559 mode was enabled, but block was missing baseFeePerGas") } return nil } diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index dfb4adf11ef..0cb160a172c 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -143,7 +143,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { return len(b) == 1 && b[0].Method == "eth_getBlockByNumber" && b[0].Args[0] == gas.Int64ToHex(41) && b[0].Args[1].(bool) && reflect.TypeOf(b[0].Result) == reflect.TypeOf(&evmtypes.Block{}) - })).Return(errors.Wrap(context.DeadlineExceeded, "some error message")).Once() + })).Return(pkgerrors.Wrap(context.DeadlineExceeded, "some error message")).Once() err := bhe.Start(testutils.Context(t)) require.NoError(t, err) @@ -177,7 +177,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) - ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, errors.New("something exploded")) + ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, pkgerrors.New("something exploded")) err := bhe.Start(testutils.Context(t)) require.NoError(t, err) @@ -200,7 +200,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) - ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(errors.New("something went wrong")) + ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(pkgerrors.New("something went wrong")) err := bhe.Start(testutils.Context(t)) require.NoError(t, err) @@ -223,7 +223,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) - ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(errors.New("this error doesn't matter")) + ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(pkgerrors.New("this error doesn't matter")) ctx, cancel := context.WithCancel(testutils.Context(t)) cancel() @@ -239,7 +239,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) - ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(errors.New("this error doesn't matter")).Run(func(_ mock.Arguments) { + ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(pkgerrors.New("this error doesn't matter")).Run(func(_ mock.Arguments) { time.Sleep(gas.MaxStartTime + 1*time.Second) }) @@ -342,7 +342,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) - ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(errors.New("something exploded")) + ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(pkgerrors.New("something exploded")) err := bhe.FetchBlocks(testutils.Context(t), cltest.Head(42)) require.Error(t, err) @@ -390,7 +390,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { elems := args.Get(1).([]rpc.BatchElem) elems[0].Result = &b43 // This errored block (42) will be ignored - elems[1].Error = errors.New("something went wrong") + elems[1].Error = pkgerrors.New("something went wrong") }) ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { return len(b) == 1 && @@ -2392,7 +2392,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { _, _, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, attempts) require.Error(t, err) - assert.True(t, errors.Is(err, commonfee.ErrConnectivity)) + assert.True(t, pkgerrors.Is(err, commonfee.ErrConnectivity)) assert.Contains(t, err.Error(), fmt.Sprintf("transaction %s has gas price of 1 kwei, which is above percentile=10%% (percentile price: 1 wei) for blocks 1 thru 1 (checking 1 blocks)", attempts[0].TxHash)) }) @@ -2505,7 +2505,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { _, _, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, attempts) require.Error(t, err) - assert.True(t, errors.Is(err, commonfee.ErrConnectivity)) + assert.True(t, pkgerrors.Is(err, commonfee.ErrConnectivity)) assert.Contains(t, err.Error(), fmt.Sprintf("transaction %s has tip cap of 25 wei, which is above percentile=10%% (percentile tip cap: 1 wei) for blocks 1 thru 1 (checking 1 blocks)", attempts[0].TxHash)) }) diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index 4d9f45a1bd4..a69be3b0d05 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -3,7 +3,7 @@ package gas import ( "context" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" @@ -99,7 +99,7 @@ func (f *fixedPriceEstimator) GetDynamicFee(_ context.Context, originalGasLimit gasTipCap := f.config.TipCapDefault() if gasTipCap == nil { - return d, 0, errors.New("cannot calculate dynamic fee: EthGasTipCapDefault was not set") + return d, 0, pkgerrors.New("cannot calculate dynamic fee: EthGasTipCapDefault was not set") } chainSpecificGasLimit, err = commonfee.ApplyMultiplier(originalGasLimit, f.config.LimitMultiplier()) if err != nil { diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 0b3ebdd0ee3..44e85af37ff 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -187,11 +187,11 @@ func (e *WrappedEvmEstimator) Name() string { func (e *WrappedEvmEstimator) Start(ctx context.Context) error { return e.StartOnce(e.Name(), func() error { if err := e.EvmEstimator.Start(ctx); err != nil { - return errors.Wrap(err, "failed to start EVMEstimator") + return pkgerrors.Wrap(err, "failed to start EVMEstimator") } if e.l1Oracle != nil { if err := e.l1Oracle.Start(ctx); err != nil { - return errors.Wrap(err, "failed to start L1Oracle") + return pkgerrors.Wrap(err, "failed to start L1Oracle") } } return nil @@ -201,9 +201,9 @@ func (e *WrappedEvmEstimator) Close() error { return e.StopOnce(e.Name(), func() error { var errEVM, errOracle error - errEVM = errors.Wrap(e.EvmEstimator.Close(), "failed to stop EVMEstimator") + errEVM = pkgerrors.Wrap(e.EvmEstimator.Close(), "failed to stop EVMEstimator") if e.l1Oracle != nil { - errOracle = errors.Wrap(e.l1Oracle.Close(), "failed to stop L1Oracle") + errOracle = pkgerrors.Wrap(e.l1Oracle.Close(), "failed to stop L1Oracle") } if errEVM != nil { @@ -277,7 +277,7 @@ func (e *WrappedEvmEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, func (e *WrappedEvmEstimator) BumpFee(ctx context.Context, originalFee EvmFee, feeLimit uint32, maxFeePrice *assets.Wei, attempts []EvmPriorAttempt) (bumpedFee EvmFee, chainSpecificFeeLimit uint32, err error) { // validate only 1 fee type is present if (!originalFee.ValidDynamic() && originalFee.Legacy == nil) || (originalFee.ValidDynamic() && originalFee.Legacy != nil) { - err = errors.New("only one dynamic or legacy fee can be defined") + err = pkgerrors.New("only one dynamic or legacy fee can be defined") return } @@ -377,13 +377,13 @@ func bumpGasPrice(cfg bumpConfig, lggr logger.SugaredLogger, currentGasPrice, or bumpedGasPrice = maxBumpedFee(lggr, currentGasPrice, bumpedGasPrice, maxGasPrice, "gas price") if bumpedGasPrice.Cmp(maxGasPrice) > 0 { - return maxGasPrice, errors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped gas price of %s would exceed configured max gas price of %s (original price was %s). %s", + return maxGasPrice, pkgerrors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped gas price of %s would exceed configured max gas price of %s (original price was %s). %s", bumpedGasPrice.String(), maxGasPrice, originalGasPrice.String(), label.NodeConnectivityProblemWarning) } else if bumpedGasPrice.Cmp(originalGasPrice) == 0 { // NOTE: This really shouldn't happen since we enforce minimums for // EVM.GasEstimator.BumpPercent and EVM.GasEstimator.BumpMin in the config validation, // but it's here anyway for a "belts and braces" approach - return bumpedGasPrice, errors.Wrapf(commonfee.ErrBump, "bumped gas price of %s is equal to original gas price of %s."+ + return bumpedGasPrice, pkgerrors.Wrapf(commonfee.ErrBump, "bumped gas price of %s is equal to original gas price of %s."+ " ACTION REQUIRED: This is a configuration error, you must increase either "+ "EVM.GasEstimator.BumpPercent or EVM.GasEstimator.BumpMin", bumpedGasPrice.String(), originalGasPrice.String()) } @@ -419,13 +419,13 @@ func bumpDynamicFee(cfg bumpConfig, feeCapBufferBlocks uint16, lggr logger.Sugar bumpedTipCap = maxBumpedFee(lggr, currentTipCap, bumpedTipCap, maxGasPrice, "tip cap") if bumpedTipCap.Cmp(maxGasPrice) > 0 { - return bumpedFee, errors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped tip cap of %s would exceed configured max gas price of %s (original fee: tip cap %s, fee cap %s). %s", + return bumpedFee, pkgerrors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped tip cap of %s would exceed configured max gas price of %s (original fee: tip cap %s, fee cap %s). %s", bumpedTipCap.String(), maxGasPrice, originalFee.TipCap.String(), originalFee.FeeCap.String(), label.NodeConnectivityProblemWarning) } else if bumpedTipCap.Cmp(originalFee.TipCap) <= 0 { // NOTE: This really shouldn't happen since we enforce minimums for // EVM.GasEstimator.BumpPercent and EVM.GasEstimator.BumpMin in the config validation, // but it's here anyway for a "belts and braces" approach - return bumpedFee, errors.Wrapf(commonfee.ErrBump, "bumped gas tip cap of %s is less than or equal to original gas tip cap of %s."+ + return bumpedFee, pkgerrors.Wrapf(commonfee.ErrBump, "bumped gas tip cap of %s is less than or equal to original gas tip cap of %s."+ " ACTION REQUIRED: This is a configuration error, you must increase either "+ "EVM.GasEstimator.BumpPercent or EVM.GasEstimator.BumpMin", bumpedTipCap.String(), originalFee.TipCap.String()) } @@ -445,7 +445,7 @@ func bumpDynamicFee(cfg bumpConfig, feeCapBufferBlocks uint16, lggr logger.Sugar } if bumpedFeeCap.Cmp(maxGasPrice) > 0 { - return bumpedFee, errors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped fee cap of %s would exceed configured max gas price of %s (original fee: tip cap %s, fee cap %s). %s", + return bumpedFee, pkgerrors.Wrapf(commonfee.ErrBumpFeeExceedsLimit, "bumped fee cap of %s would exceed configured max gas price of %s (original fee: tip cap %s, fee cap %s). %s", bumpedFeeCap.String(), maxGasPrice, originalFee.TipCap.String(), originalFee.FeeCap.String(), label.NodeConnectivityProblemWarning) } diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index 95a7a471eba..9c0e63a602b 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -4,7 +4,7 @@ import ( "math/big" "testing" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -201,9 +201,9 @@ func TestWrappedEvmEstimator(t *testing.T) { oracle := rollupMocks.NewL1Oracle(t) evmEstimatorKey := "evm" - evmEstimatorError := errors.New("evm error") + evmEstimatorError := pkgerrors.New("evm error") oracleKey := "oracle" - oracleError := errors.New("oracle error") + oracleError := pkgerrors.New("oracle error") evmEstimator.On("HealthReport").Return(map[string]error{evmEstimatorKey: evmEstimatorError}).Twice() oracle.On("HealthReport").Return(map[string]error{oracleKey: oracleError}).Once() @@ -211,14 +211,14 @@ func TestWrappedEvmEstimator(t *testing.T) { estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) report := estimator.HealthReport() - require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) + require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) require.Nil(t, report[oracleKey]) require.NotNil(t, report[mockEstimatorName]) estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) report = estimator.HealthReport() - require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) - require.True(t, errors.Is(report[oracleKey], oracleError)) + require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) + require.True(t, pkgerrors.Is(report[oracleKey], oracleError)) require.NotNil(t, report[mockEstimatorName]) }) } diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index fe6483f40f3..d58a1155b91 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -8,7 +8,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -138,14 +138,14 @@ func (o *SuggestedPriceEstimator) forceRefresh(ctx context.Context) (err error) select { case o.chForceRefetch <- ch: case <-o.chStop: - return errors.New("estimator stopped") + return pkgerrors.New("estimator stopped") case <-ctx.Done(): return ctx.Err() } select { case <-ch: case <-o.chStop: - return errors.New("estimator stopped") + return pkgerrors.New("estimator stopped") case <-ctx.Done(): return ctx.Err() } @@ -155,12 +155,12 @@ func (o *SuggestedPriceEstimator) forceRefresh(ctx context.Context) (err error) func (o *SuggestedPriceEstimator) OnNewLongestChain(context.Context, *evmtypes.Head) {} func (*SuggestedPriceEstimator) GetDynamicFee(_ context.Context, _ uint32, _ *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint32, err error) { - err = errors.New("dynamic fees are not implemented for this estimator") + err = pkgerrors.New("dynamic fees are not implemented for this estimator") return } func (*SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, _ uint32, _ *assets.Wei, _ []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint32, err error) { - err = errors.New("dynamic fees are not implemented for this estimator") + err = pkgerrors.New("dynamic fees are not implemented for this estimator") return } @@ -171,19 +171,19 @@ func (o *SuggestedPriceEstimator) GetLegacyGas(ctx context.Context, _ []byte, Ga err = o.forceRefresh(ctx) } if gasPrice = o.getGasPrice(); gasPrice == nil { - err = errors.New("failed to estimate gas; gas price not set") + err = pkgerrors.New("failed to estimate gas; gas price not set") return } o.logger.Debugw("GetLegacyGas", "GasPrice", gasPrice, "GasLimit", GasLimit) }) if !ok { - return nil, 0, errors.New("estimator is not started") + return nil, 0, pkgerrors.New("estimator is not started") } else if err != nil { return } // For L2 chains, submitting a transaction that is not priced high enough will cause the call to fail, so if the cap is lower than the RPC suggested gas price, this transaction cannot succeed if gasPrice != nil && gasPrice.Cmp(maxGasPriceWei) > 0 { - return nil, 0, errors.Errorf("estimated gas price: %s is greater than the maximum gas price configured: %s", gasPrice.String(), maxGasPriceWei.String()) + return nil, 0, pkgerrors.Errorf("estimated gas price: %s is greater than the maximum gas price configured: %s", gasPrice.String(), maxGasPriceWei.String()) } return } @@ -203,18 +203,18 @@ func (o *SuggestedPriceEstimator) BumpLegacyGas(ctx context.Context, originalFee } err = o.forceRefresh(ctx) if newGasPrice = o.getGasPrice(); newGasPrice == nil { - err = errors.New("failed to refresh and return gas; gas price not set") + err = pkgerrors.New("failed to refresh and return gas; gas price not set") return } o.logger.Debugw("GasPrice", newGasPrice, "GasLimit", feeLimit) }) if !ok { - return nil, 0, errors.New("estimator is not started") + return nil, 0, pkgerrors.New("estimator is not started") } else if err != nil { return } if newGasPrice != nil && newGasPrice.Cmp(maxGasPriceWei) > 0 { - return nil, 0, errors.Errorf("estimated gas price: %s is greater than the maximum gas price configured: %s", newGasPrice.String(), maxGasPriceWei.String()) + return nil, 0, pkgerrors.Errorf("estimated gas price: %s is greater than the maximum gas price configured: %s", newGasPrice.String(), maxGasPriceWei.String()) } // Add a buffer on top of the gas price returned by the RPC. // Bump logic when using the suggested gas price from an RPC is realistically only needed when there is increased volatility in gas price. diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 9006554564d..c09582774b8 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -87,7 +87,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { client := mocks.NewRPCClient(t) o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) + client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) @@ -203,7 +203,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { client := mocks.NewRPCClient(t) o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) + client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) @@ -219,7 +219,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { res := args.Get(1).(*hexutil.Big) (*big.Int)(res).SetInt64(40) }).Once() - client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) + client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(pkgerrors.New("kaboom")) servicetest.RunHealthy(t, o) diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index 3ba9c0863da..e5131aca422 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -155,7 +155,7 @@ func Test_HeadListener_SubscriptionErr(t *testing.T) { closeErr bool }{ {"nil error", nil, false}, - {"socket error", errors.New("close 1006 (abnormal closure): unexpected EOF"), false}, + {"socket error", pkgerrors.New("close 1006 (abnormal closure): unexpected EOF"), false}, {"close Err channel", nil, true}, } diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 859f6764b63..a1957388b9b 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -6,7 +6,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/jmoiron/sqlx" @@ -47,7 +47,7 @@ func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) e :hash, :number, :parent_hash, :created_at, :timestamp, :l1_block_number, :evm_chain_id, :base_fee_per_gas) ON CONFLICT (evm_chain_id, hash) DO NOTHING` err := q.ExecQNamed(query, head) - return errors.Wrap(err, "IdempotentInsertHead failed to insert head") + return pkgerrors.Wrap(err, "IdempotentInsertHead failed to insert head") } func (orm *orm) TrimOldHeads(ctx context.Context, n uint) (err error) { @@ -69,17 +69,17 @@ func (orm *orm) LatestHead(ctx context.Context) (head *evmtypes.Head, err error) head = new(evmtypes.Head) q := orm.q.WithOpts(pg.WithParentCtx(ctx)) err = q.Get(head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT 1`, orm.chainID) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } - err = errors.Wrap(err, "LatestHead failed") + err = pkgerrors.Wrap(err, "LatestHead failed") return } func (orm *orm) LatestHeads(ctx context.Context, limit uint) (heads []*evmtypes.Head, err error) { q := orm.q.WithOpts(pg.WithParentCtx(ctx)) err = q.Select(&heads, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 ORDER BY number DESC, created_at DESC, id DESC LIMIT $2`, orm.chainID, limit) - err = errors.Wrap(err, "LatestHeads failed") + err = pkgerrors.Wrap(err, "LatestHeads failed") return } @@ -87,7 +87,7 @@ func (orm *orm) HeadByHash(ctx context.Context, hash common.Hash) (head *evmtype q := orm.q.WithOpts(pg.WithParentCtx(ctx)) head = new(evmtypes.Head) err = q.Get(head, `SELECT * FROM evm.heads WHERE evm_chain_id = $1 AND hash = $2`, orm.chainID, hash) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } return head, err diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index 8321dd30bfe..c4db2a4826c 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -773,13 +773,13 @@ func (n *NullBroadcaster) TrackedAddressesCount() uint32 { return 0 } func (n *NullBroadcaster) WasAlreadyConsumed(lb Broadcast, qopts ...pg.QOpt) (bool, error) { - return false, errors.New(n.ErrMsg) + return false, pkgerrors.New(n.ErrMsg) } func (n *NullBroadcaster) MarkConsumed(lb Broadcast, qopts ...pg.QOpt) error { - return errors.New(n.ErrMsg) + return pkgerrors.New(n.ErrMsg) } func (n *NullBroadcaster) MarkManyConsumed(lbs []Broadcast, qopts ...pg.QOpt) error { - return errors.New(n.ErrMsg) + return pkgerrors.New(n.ErrMsg) } func (n *NullBroadcaster) AddDependents(int) {} diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index 51ed9f2f132..25012d5c8e0 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/jmoiron/sqlx" @@ -75,7 +75,7 @@ func (o *orm) WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID i } q := o.q.WithOpts(qopts...) err = q.Get(&consumed, query, args...) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return false, nil } return consumed, err @@ -91,7 +91,7 @@ func (o *orm) FindBroadcasts(fromBlockNum int64, toBlockNum int64) ([]LogBroadca ` err := o.q.Select(&broadcasts, query, fromBlockNum, toBlockNum, o.evmChainID) if err != nil { - return nil, errors.Wrap(err, "failed to find log broadcasts") + return nil, pkgerrors.Wrap(err, "failed to find log broadcasts") } return broadcasts, err } @@ -102,7 +102,7 @@ func (o *orm) CreateBroadcast(blockHash common.Hash, blockNumber uint64, logInde INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) VALUES ($1, $2, $3, $4, NOW(), NOW(), false, $5) `, blockHash, blockNumber, logIndex, jobID, o.evmChainID) - return errors.Wrap(err, "failed to create log broadcast") + return pkgerrors.Wrap(err, "failed to create log broadcast") } func (o *orm) MarkBroadcastConsumed(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, qopts ...pg.QOpt) error { @@ -113,7 +113,7 @@ func (o *orm) MarkBroadcastConsumed(blockHash common.Hash, blockNumber uint64, l ON CONFLICT (job_id, block_hash, log_index, evm_chain_id) DO UPDATE SET consumed = true, updated_at = NOW() `, blockHash, blockNumber, logIndex, jobID, o.evmChainID) - return errors.Wrap(err, "failed to mark log broadcast as consumed") + return pkgerrors.Wrap(err, "failed to mark log broadcast as consumed") } // MarkBroadcastsConsumed marks many broadcasts as consumed. @@ -150,7 +150,7 @@ SET consumed = true, updated_at = NOW(); } q := o.q.WithOpts(qopts...) _, err := q.NamedExec(query, inputs) - return errors.Wrap(err, "mark broadcasts consumed") + return pkgerrors.Wrap(err, "mark broadcasts consumed") } // MarkBroadcastsUnconsumed implements the ORM interface. @@ -162,7 +162,7 @@ func (o *orm) MarkBroadcastsUnconsumed(fromBlock int64, qopts ...pg.QOpt) error WHERE block_number >= $1 AND evm_chain_id = $2 `, fromBlock, o.evmChainID) - return errors.Wrap(err, "failed to mark broadcasts unconsumed") + return pkgerrors.Wrap(err, "failed to mark broadcasts unconsumed") } func (o *orm) Reinitialize(qopts ...pg.QOpt) (*int64, error) { @@ -201,7 +201,7 @@ func (o *orm) SetPendingMinBlock(blockNumber *int64, qopts ...pg.QOpt) error { INSERT INTO log_broadcasts_pending (evm_chain_id, block_number, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (evm_chain_id) DO UPDATE SET block_number = $3, updated_at = NOW() `, o.evmChainID, blockNumber, blockNumber) - return errors.Wrap(err, "failed to set pending broadcast block number") + return pkgerrors.Wrap(err, "failed to set pending broadcast block number") } func (o *orm) GetPendingMinBlock(qopts ...pg.QOpt) (*int64, error) { @@ -210,10 +210,10 @@ func (o *orm) GetPendingMinBlock(qopts ...pg.QOpt) (*int64, error) { err := q.Get(&blockNumber, ` SELECT block_number FROM log_broadcasts_pending WHERE evm_chain_id = $1 `, o.evmChainID) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } else if err != nil { - return nil, errors.Wrap(err, "failed to get broadcasts pending number") + return nil, pkgerrors.Wrap(err, "failed to get broadcasts pending number") } return blockNumber, nil } @@ -227,10 +227,10 @@ func (o *orm) getUnconsumedMinBlock(qopts ...pg.QOpt) (*int64, error) { AND consumed = false AND block_number IS NOT NULL `, o.evmChainID) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } else if err != nil { - return nil, errors.Wrap(err, "failed to get unconsumed broadcasts min block number") + return nil, pkgerrors.Wrap(err, "failed to get unconsumed broadcasts min block number") } return blockNumber, nil } @@ -243,7 +243,7 @@ func (o *orm) removeUnconsumed(qopts ...pg.QOpt) error { AND consumed = false AND block_number IS NOT NULL `, o.evmChainID) - return errors.Wrap(err, "failed to delete unconsumed broadcasts") + return pkgerrors.Wrap(err, "failed to delete unconsumed broadcasts") } // LogBroadcast - data from log_broadcasts table columns diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index 346a6776e86..1bb6c8c59c0 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -119,12 +119,12 @@ func (r *registrations) handlersWithGreaterConfs(confs uint32) (handlersWithGrea // maps modified are only used for checks func (r *registrations) checkAddSubscriber(sub *subscriber) error { if sub.opts.MinIncomingConfirmations <= 0 { - return errors.Errorf("LogBroadcaster requires that MinIncomingConfirmations must be at least 1 (got %v). Logs must have been confirmed in at least 1 block, it does not support reading logs from the mempool before they have been mined", sub.opts.MinIncomingConfirmations) + return pkgerrors.Errorf("LogBroadcaster requires that MinIncomingConfirmations must be at least 1 (got %v). Logs must have been confirmed in at least 1 block, it does not support reading logs from the mempool before they have been mined", sub.opts.MinIncomingConfirmations) } jobID := sub.listener.JobID() if _, exists := r.registeredSubs[sub]; exists { - return errors.Errorf("Cannot add subscriber %p for job ID %v: already added", sub, jobID) + return pkgerrors.Errorf("Cannot add subscriber %p for job ID %v: already added", sub, jobID) } r.registeredSubs[sub] = struct{}{} addrs, exists := r.jobIDAddrs[jobID] @@ -132,7 +132,7 @@ func (r *registrations) checkAddSubscriber(sub *subscriber) error { r.jobIDAddrs[jobID] = make(map[common.Address]struct{}) } if _, exists := addrs[sub.opts.Contract]; exists { - return errors.Errorf("Cannot add subscriber %p: only one subscription is allowed per jobID/contract address. There is already a subscription with job ID %v listening on %s", sub, jobID, sub.opts.Contract.Hex()) + return pkgerrors.Errorf("Cannot add subscriber %p: only one subscription is allowed per jobID/contract address. There is already a subscription with job ID %v listening on %s", sub, jobID, sub.opts.Contract.Hex()) } r.jobIDAddrs[jobID][sub.opts.Contract] = struct{}{} return nil @@ -165,16 +165,16 @@ func (r *registrations) removeSubscriber(sub *subscriber) (needsResubscribe bool func (r *registrations) checkRemoveSubscriber(sub *subscriber) error { jobID := sub.listener.JobID() if _, exists := r.registeredSubs[sub]; !exists { - return errors.Errorf("Cannot remove subscriber %p for job ID %v: not registered", sub, jobID) + return pkgerrors.Errorf("Cannot remove subscriber %p for job ID %v: not registered", sub, jobID) } delete(r.registeredSubs, sub) addrs, exists := r.jobIDAddrs[jobID] if !exists { - return errors.Errorf("Cannot remove subscriber %p: jobIDAddrs was missing job ID %v", sub, jobID) + return pkgerrors.Errorf("Cannot remove subscriber %p: jobIDAddrs was missing job ID %v", sub, jobID) } _, exists = addrs[sub.opts.Contract] if !exists { - return errors.Errorf("Cannot remove subscriber %p: jobIDAddrs was missing address %s", sub, sub.opts.Contract.Hex()) + return pkgerrors.Errorf("Cannot remove subscriber %p: jobIDAddrs was missing address %s", sub, sub.opts.Contract.Hex()) } delete(r.jobIDAddrs[jobID], sub.opts.Contract) if len(r.jobIDAddrs[jobID]) == 0 { diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index 05d591042f4..8d92b8d29f6 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -5,13 +5,13 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) var ( - ErrDisabled = errors.New("log poller disabled") + ErrDisabled = pkgerrors.New("log poller disabled") LogPollerDisabled LogPoller = disabled{} ) diff --git a/core/chains/evm/logpoller/helper_test.go b/core/chains/evm/logpoller/helper_test.go index cb0fbd247fc..3215a7ec20c 100644 --- a/core/chains/evm/logpoller/helper_test.go +++ b/core/chains/evm/logpoller/helper_test.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -99,7 +99,7 @@ func (th *TestHarness) PollAndSaveLogs(ctx context.Context, currentBlockNumber i func (th *TestHarness) assertDontHave(t *testing.T, start, end int) { for i := start; i < end; i++ { _, err := th.ORM.SelectBlockByNumber(int64(i)) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) } } diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index ba617a2178b..a19bbfda7f1 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -89,9 +89,9 @@ type Client interface { var ( _ LogPollerTest = &logPoller{} - ErrReplayRequestAborted = errors.New("aborted, replay request cancelled") - ErrReplayInProgress = errors.New("replay request cancelled, but replay is already in progress") - ErrLogPollerShutdown = errors.New("replay aborted due to log poller shutdown") + ErrReplayRequestAborted = pkgerrors.New("aborted, replay request cancelled") + ErrReplayInProgress = pkgerrors.New("replay request cancelled, but replay is already in progress") + ErrLogPollerShutdown = pkgerrors.New("replay aborted due to log poller shutdown") ) type logPoller struct { @@ -226,20 +226,20 @@ func (filter *Filter) Contains(other *Filter) bool { // 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") + return pkgerrors.Errorf("at least one address must be specified") } if len(filter.EventSigs) == 0 { - return errors.Errorf("at least one event must be specified") + return pkgerrors.Errorf("at least one event must be specified") } for _, eventSig := range filter.EventSigs { if eventSig == [common.HashLength]byte{} { - return errors.Errorf("empty event sig") + return pkgerrors.Errorf("empty event sig") } } for _, addr := range filter.Addresses { if addr == [common.AddressLength]byte{} { - return errors.Errorf("empty address") + return pkgerrors.Errorf("empty address") } } @@ -256,7 +256,7 @@ func (lp *logPoller) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { } if err := lp.orm.InsertFilter(filter, qopts...); err != nil { - return errors.Wrap(err, "error inserting filter") + return pkgerrors.Wrap(err, "error inserting filter") } lp.filters[filter.Name] = filter lp.filterDirty = true @@ -277,7 +277,7 @@ func (lp *logPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { } if err := lp.orm.DeleteFilter(name, qopts...); err != nil { - return errors.Wrap(err, "error deleting filter") + return pkgerrors.Wrap(err, "error deleting filter") } delete(lp.filters, name) lp.filterDirty = true @@ -352,13 +352,13 @@ func (lp *logPoller) Replay(ctx context.Context, fromBlock int64) error { return err } if fromBlock < 1 || fromBlock > latest.Number { - return errors.Errorf("Invalid replay block number %v, acceptable range [1, %v]", fromBlock, latest.Number) + return pkgerrors.Errorf("Invalid replay block number %v, acceptable range [1, %v]", fromBlock, latest.Number) } // Block until replay notification accepted or cancelled. select { case lp.replayStart <- fromBlock: case <-ctx.Done(): - return errors.Wrap(ErrReplayRequestAborted, ctx.Err().Error()) + return pkgerrors.Wrap(ErrReplayRequestAborted, ctx.Err().Error()) } // Block until replay complete or cancelled. select { @@ -423,7 +423,7 @@ func (lp *logPoller) HealthReport() map[string]error { func (lp *logPoller) GetReplayFromBlock(ctx context.Context, requested int64) (int64, error) { lastProcessed, err := lp.orm.SelectLatestBlock(pg.WithParentCtx(ctx)) if err != nil { - if !errors.Is(err, sql.ErrNoRows) { + if !pkgerrors.Is(err, sql.ErrNoRows) { // Real DB error return 0, err } @@ -449,7 +449,7 @@ func (lp *logPoller) run() { filters, err := lp.orm.LoadFilters(pg.WithParentCtx(lp.ctx)) if err != nil { - return errors.Wrapf(err, "Failed to load initial filters from db, retrying") + return pkgerrors.Wrapf(err, "Failed to load initial filters from db, retrying") } lp.filters = filters @@ -503,7 +503,7 @@ func (lp *logPoller) run() { var start int64 lastProcessed, err := lp.orm.SelectLatestBlock(pg.WithParentCtx(lp.ctx)) if err != nil { - if !errors.Is(err, sql.ErrNoRows) { + if !pkgerrors.Is(err, sql.ErrNoRows) { // Assume transient db reading issue, retry forever. lp.lggr.Errorw("unable to get starting block", "err", err) continue @@ -586,7 +586,7 @@ func (lp *logPoller) BackupPollAndSaveLogs(ctx context.Context, backupPollerBloc if lp.backupPollerNextBlock == 0 { lastProcessed, err := lp.orm.SelectLatestBlock(pg.WithParentCtx(ctx)) if err != nil { - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { lp.lggr.Warnw("Backup log poller ran before first successful log poller run, skipping") } else { lp.lggr.Errorw("Backup log poller unable to get starting block", "err", err) @@ -687,7 +687,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { gethLogs, err := lp.ec.FilterLogs(ctx, lp.Filter(big.NewInt(from), big.NewInt(to), nil)) if err != nil { var rpcErr client.JsonError - if errors.As(err, &rpcErr) { + if pkgerrors.As(err, &rpcErr) { if rpcErr.Code != jsonRpcLimitExceeded { lp.lggr.Errorw("Unable to query for logs", "err", err, "from", from, "to", to) return err @@ -740,20 +740,20 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // Additional sanity checks, don't necessarily trust the RPC. if currentBlock == nil { lp.lggr.Errorf("Unexpected nil block from RPC", "currentBlockNumber", currentBlockNumber) - return nil, errors.Errorf("Got nil block for %d", currentBlockNumber) + return nil, pkgerrors.Errorf("Got nil block for %d", currentBlockNumber) } if currentBlock.Number != currentBlockNumber { lp.lggr.Warnw("Unable to get currentBlock, rpc returned incorrect block", "currentBlockNumber", currentBlockNumber, "got", currentBlock.Number) - return nil, errors.Errorf("Block mismatch have %d want %d", currentBlock.Number, currentBlockNumber) + return nil, pkgerrors.Errorf("Block mismatch have %d want %d", currentBlock.Number, currentBlockNumber) } } // Does this currentBlock point to the same parent that we have saved? // If not, there was a reorg, so we need to rewind. expectedParent, err1 := lp.orm.SelectBlockByNumber(currentBlockNumber-1, pg.WithParentCtx(ctx)) - if err1 != nil && !errors.Is(err1, sql.ErrNoRows) { + if err1 != nil && !pkgerrors.Is(err1, sql.ErrNoRows) { // If err is not a 'no rows' error, assume transient db issue and retry lp.lggr.Warnw("Unable to read latestBlockNumber currentBlock saved", "err", err1, "currentBlockNumber", currentBlockNumber) - return nil, errors.New("Unable to read latestBlockNumber currentBlock saved") + return nil, pkgerrors.New("Unable to read latestBlockNumber currentBlock saved") } // We will not have the previous currentBlock on initial poll. havePreviousBlock := err1 == nil @@ -769,7 +769,7 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren blockAfterLCA, err2 := lp.findBlockAfterLCA(ctx, currentBlock, expectedParent.FinalizedBlockNumber) if err2 != nil { lp.lggr.Warnw("Unable to find LCA after reorg, retrying", "err", err2) - return nil, errors.New("Unable to find LCA after reorg, retrying") + return nil, pkgerrors.New("Unable to find LCA after reorg, retrying") } lp.lggr.Infow("Reorg detected", "blockAfterLCA", blockAfterLCA.Number, "currentBlockNumber", currentBlockNumber) @@ -950,7 +950,7 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He } } 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") + rerr := pkgerrors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) return nil, rerr } @@ -1133,7 +1133,7 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts } if len(blocksNotFound) > 0 { - return nil, errors.Errorf("blocks were not found in db or RPC call: %v", blocksNotFound) + return nil, pkgerrors.Errorf("blocks were not found in db or RPC call: %v", blocksNotFound) } return blocks, nil @@ -1205,16 +1205,16 @@ func (lp *logPoller) batchFetchBlocks(ctx context.Context, blocksRequested []str block, is := r.Result.(*evmtypes.Head) if !is { - return nil, errors.Errorf("expected result to be a %T, got %T", &evmtypes.Head{}, r.Result) + return nil, pkgerrors.Errorf("expected result to be a %T, got %T", &evmtypes.Head{}, r.Result) } if block == nil { - return nil, errors.New("invariant violation: got nil block") + return nil, pkgerrors.New("invariant violation: got nil block") } if block.Hash == (common.Hash{}) { - return nil, errors.Errorf("missing block hash for block number: %d", block.Number) + return nil, pkgerrors.Errorf("missing block hash for block number: %d", block.Number) } if block.Number < 0 { - return nil, errors.Errorf("expected block number to be >= to 0, got %d", block.Number) + return nil, pkgerrors.Errorf("expected block number to be >= to 0, got %d", block.Number) } blocks = append(blocks, block) } diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index 124c16d26f3..0bde65e5556 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -286,7 +286,7 @@ func TestLogPoller_Replay(t *testing.T) { // Replay() should return error code received from replayComplete t.Run("returns error code on replay complete", func(t *testing.T) { ctx := testutils.Context(t) - anyErr := errors.New("any error") + anyErr := pkgerrors.New("any error") done := make(chan struct{}) go func() { defer close(done) @@ -412,7 +412,7 @@ func TestLogPoller_Replay(t *testing.T) { t.Cleanup(lp.reset) servicetest.Run(t, lp) - anyErr := errors.New("async error") + anyErr := pkgerrors.New("async error") observedLogs.TakeAll() lp.ReplayAsync(4) diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index c0e870870e6..f61845b870f 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -361,7 +361,7 @@ func (o *DbORM) insertLogsWithinTx(logs []Log, tx pg.Queryer) error { ) if err != nil { - if errors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { + if pkgerrors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { // In case of DB timeouts, try to insert again with a smaller batch upto a limit batchInsertSize /= 2 i -= batchInsertSize // counteract +=batchInsertSize on next loop iteration @@ -376,7 +376,7 @@ func (o *DbORM) insertLogsWithinTx(logs []Log, tx pg.Queryer) error { func (o *DbORM) validateLogs(logs []Log) error { for _, log := range logs { if o.chainID.Cmp(log.EvmChainId.ToInt()) != 0 { - return errors.Errorf("invalid chainID in log got %v want %v", log.EvmChainId.ToInt(), o.chainID) + return pkgerrors.Errorf("invalid chainID in log got %v want %v", log.EvmChainId.ToInt(), o.chainID) } } return nil @@ -475,7 +475,7 @@ func (o *DbORM) SelectLogsWithSigs(start, end int64, address common.Address, eve AND event_sig = ANY(:event_sig_array) AND block_number BETWEEN :start_block AND :end_block ORDER BY (block_number, log_index)`, args) - if errors.Is(err, sql.ErrNoRows) { + if pkgerrors.Is(err, sql.ErrNoRows) { return nil, nil } return logs, err @@ -526,7 +526,7 @@ func (o *DbORM) SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresse ORDER BY block_number ASC`, nestedBlockNumberQuery(confs)) var logs []Log if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { - return nil, errors.Wrap(err, "failed to execute query") + return nil, pkgerrors.Wrap(err, "failed to execute query") } return logs, nil } diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 8f89a237fd4..655a7295dab 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jackc/pgx/v4" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -205,17 +205,17 @@ func TestORM(t *testing.T) { require.NoError(t, o1.DeleteLogsAndBlocksAfter(10)) _, err = o1.SelectBlockByHash(common.HexToHash("0x1234")) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // Delete blocks from another chain. require.NoError(t, o2.DeleteLogsAndBlocksAfter(11)) _, err = o2.SelectBlockByHash(common.HexToHash("0x1234")) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // Delete blocks after should also delete block 12. _, err = o2.SelectBlockByHash(common.HexToHash("0x1235")) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // Should be able to insert and read back a log. topic := common.HexToHash("0x1599") @@ -331,7 +331,7 @@ func TestORM(t *testing.T) { // With no blocks, should be an error _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // With block 10, only 0 confs should work require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 10, time.Now(), 0)) log, err := o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) @@ -339,7 +339,7 @@ func TestORM(t *testing.T) { assert.Equal(t, int64(10), log.BlockNumber) _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 1) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // With block 12, anything <=2 should work require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 11, time.Now(), 0)) require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 12, time.Now(), 0)) @@ -351,7 +351,7 @@ func TestORM(t *testing.T) { require.NoError(t, err) _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 3) require.Error(t, err) - assert.True(t, errors.Is(err, sql.ErrNoRows)) + assert.True(t, pkgerrors.Is(err, sql.ErrNoRows)) // Required for confirmations to work require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 13, time.Now(), 0)) diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index bb271ad1d46..16e2fd527bf 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -9,7 +9,7 @@ import ( "time" gethCommon "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -231,7 +231,7 @@ func ApproximateFloat64(e *assets.Eth) (float64, error) { bf := new(big.Float).Quo(ef, weif) f64, _ := bf.Float64() if f64 == math.Inf(1) || f64 == math.Inf(-1) { - return math.Inf(1), errors.New("assets.Eth.Float64: Could not approximate Eth value into float") + return math.Inf(1), pkgerrors.New("assets.Eth.Float64: Could not approximate Eth value into float") } return f64, nil } diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index 246d5d0759f..85e0ec669bf 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/onsi/gomega" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -123,7 +123,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt). Once(). - Return(nil, errors.New("a little easter egg for the 4chan link marines error")) + Return(nil, pkgerrors.New("a little easter egg for the 4chan link marines error")) servicetest.RunHealthy(t, bm) diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index e37f0e4d2d8..892920c0f67 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" @@ -59,7 +59,7 @@ func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx, keySpecificMaxGasPriceWei := c.feeConfig.PriceMaxKey(etx.FromAddress) fee, feeLimit, err = c.EvmFeeEstimator.GetFee(ctx, etx.EncodedPayload, etx.FeeLimit, keySpecificMaxGasPriceWei, opts...) if err != nil { - return attempt, fee, feeLimit, true, errors.Wrap(err, "failed to get fee") // estimator errors are retryable + return attempt, fee, feeLimit, true, pkgerrors.Wrap(err, "failed to get fee") // estimator errors are retryable } attempt, retryable, err = c.NewCustomTxAttempt(ctx, etx, fee, feeLimit, txType, lggr) @@ -73,7 +73,7 @@ func (c *evmTxAttemptBuilder) NewBumpTxAttempt(ctx context.Context, etx Tx, prev bumpedFee, bumpedFeeLimit, err = c.EvmFeeEstimator.BumpFee(ctx, previousAttempt.TxFee, etx.FeeLimit, keySpecificMaxGasPriceWei, newEvmPriorAttempts(priorAttempts)) if err != nil { - return attempt, bumpedFee, bumpedFeeLimit, true, errors.Wrap(err, "failed to bump fee") // estimator errors are retryable + return attempt, bumpedFee, bumpedFeeLimit, true, pkgerrors.Wrap(err, "failed to bump fee") // estimator errors are retryable } attempt, retryable, err = c.NewCustomTxAttempt(ctx, etx, bumpedFee, bumpedFeeLimit, previousAttempt.TxType, lggr) @@ -86,7 +86,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(ctx context.Context, etx Tx, fe switch txType { case 0x0: // legacy if fee.Legacy == nil { - err = errors.Errorf("Attempt %v is a type 0 transaction but estimator did not return legacy fee bump", attempt.ID) + err = pkgerrors.Errorf("Attempt %v is a type 0 transaction but estimator did not return legacy fee bump", attempt.ID) logger.Sugared(lggr).AssumptionViolation(err.Error()) return attempt, false, err // not retryable } @@ -94,7 +94,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(ctx context.Context, etx Tx, fe return attempt, true, err case 0x2: // dynamic, EIP1559 if !fee.ValidDynamic() { - err = errors.Errorf("Attempt %v is a type 2 transaction but estimator did not return dynamic fee bump", attempt.ID) + err = pkgerrors.Errorf("Attempt %v is a type 2 transaction but estimator did not return dynamic fee bump", attempt.ID) logger.Sugared(lggr).AssumptionViolation(err.Error()) return attempt, false, err // not retryable } @@ -104,7 +104,7 @@ func (c *evmTxAttemptBuilder) NewCustomTxAttempt(ctx context.Context, etx Tx, fe }, gasLimit) return attempt, true, err default: - err = errors.Errorf("invariant violation: Attempt %v had unrecognised transaction type %v"+ + err = pkgerrors.Errorf("invariant violation: Attempt %v had unrecognised transaction type %v"+ "This is a bug! Please report to https://github.com/smartcontractkit/chainlink/issues", attempt.ID, attempt.TxType) logger.Sugared(lggr).AssumptionViolation(err.Error()) return attempt, false, err // not retryable @@ -117,7 +117,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(ctx context.Context, nonce evmty payload := []byte{} if fee.Legacy == nil { - return attempt, errors.New("NewEmptyTranscation: legacy fee cannot be nil") + return attempt, pkgerrors.New("NewEmptyTranscation: legacy fee cannot be nil") } tx := newLegacyTransaction( @@ -132,7 +132,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(ctx context.Context, nonce evmty transaction := types.NewTx(&tx) hash, signedTxBytes, err := c.SignTx(ctx, fromAddress, transaction) if err != nil { - return attempt, errors.Wrapf(err, "error using account %s to sign empty transaction", fromAddress.String()) + return attempt, pkgerrors.Wrapf(err, "error using account %s to sign empty transaction", fromAddress.String()) } attempt.SignedRawTx = signedTxBytes @@ -143,7 +143,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(ctx context.Context, nonce evmty func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(ctx context.Context, etx Tx, fee gas.DynamicFee, gasLimit uint32) (attempt TxAttempt, err error) { if err = validateDynamicFeeGas(c.feeConfig, c.feeConfig.TipCapMin(), fee, gasLimit, etx); err != nil { - return attempt, errors.Wrap(err, "error validating gas") + return attempt, pkgerrors.Wrap(err, "error validating gas") } d := newDynamicFeeTransaction( @@ -190,25 +190,25 @@ func validateDynamicFeeGas(kse keySpecificEstimator, tipCapMinimum *assets.Wei, // Assertions from: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md // Prevent impossibly large numbers if gasFeeCap.ToInt().Cmp(Max256BitUInt) > 0 { - return errors.New("impossibly large fee cap") + return pkgerrors.New("impossibly large fee cap") } if gasTipCap.ToInt().Cmp(Max256BitUInt) > 0 { - return errors.New("impossibly large tip cap") + return pkgerrors.New("impossibly large tip cap") } // The total must be at least as large as the tip if gasFeeCap.Cmp(gasTipCap) < 0 { - return errors.Errorf("gas fee cap must be greater than or equal to gas tip cap (fee cap: %s, tip cap: %s)", gasFeeCap.String(), gasTipCap.String()) + return pkgerrors.Errorf("gas fee cap must be greater than or equal to gas tip cap (fee cap: %s, tip cap: %s)", gasFeeCap.String(), gasTipCap.String()) } // Configuration sanity-check max := kse.PriceMaxKey(etx.FromAddress) if gasFeeCap.Cmp(max) > 0 { - return errors.Errorf("cannot create tx attempt: specified gas fee cap of %s would exceed max configured gas price of %s for key %s", gasFeeCap.String(), max.String(), etx.FromAddress.String()) + return pkgerrors.Errorf("cannot create tx attempt: specified gas fee cap of %s would exceed max configured gas price of %s for key %s", gasFeeCap.String(), max.String(), etx.FromAddress.String()) } // Tip must be above minimum minTip := tipCapMinimum if gasTipCap.Cmp(minTip) < 0 { - return errors.Errorf("cannot create tx attempt: specified gas tip cap of %s is below min configured gas tip of %s for key %s", gasTipCap.String(), minTip.String(), etx.FromAddress.String()) + return pkgerrors.Errorf("cannot create tx attempt: specified gas tip cap of %s is below min configured gas tip of %s for key %s", gasTipCap.String(), minTip.String(), etx.FromAddress.String()) } return nil } @@ -228,7 +228,7 @@ func newDynamicFeeTransaction(nonce uint64, to common.Address, value *big.Int, g func (c *evmTxAttemptBuilder) newLegacyAttempt(ctx context.Context, etx Tx, gasPrice *assets.Wei, gasLimit uint32) (attempt TxAttempt, err error) { if err = validateLegacyGas(ctx, c.feeConfig, c.feeConfig.PriceMin(), gasPrice, gasLimit, etx); err != nil { - return attempt, errors.Wrap(err, "error validating gas") + return attempt, pkgerrors.Wrap(err, "error validating gas") } tx := newLegacyTransaction( @@ -243,7 +243,7 @@ func (c *evmTxAttemptBuilder) newLegacyAttempt(ctx context.Context, etx Tx, gasP transaction := types.NewTx(&tx) hash, signedTxBytes, err := c.SignTx(ctx, etx.FromAddress, transaction) if err != nil { - return attempt, errors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress, etx.ID) + return attempt, pkgerrors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress, etx.ID) } attempt.State = txmgrtypes.TxAttemptInProgress @@ -266,11 +266,11 @@ func validateLegacyGas(ctx context.Context, kse keySpecificEstimator, minGasPric } max := kse.PriceMaxKey(etx.FromAddress) if gasPrice.Cmp(max) > 0 { - return errors.Errorf("cannot create tx attempt: specified gas price of %s would exceed max configured gas price of %s for key %s", gasPrice.String(), max.String(), etx.FromAddress.String()) + return pkgerrors.Errorf("cannot create tx attempt: specified gas price of %s would exceed max configured gas price of %s for key %s", gasPrice.String(), max.String(), etx.FromAddress.String()) } min := minGasPriceWei if gasPrice.Cmp(min) < 0 { - return errors.Errorf("cannot create tx attempt: specified gas price of %s is below min configured gas price of %s for key %s", gasPrice.String(), min.String(), etx.FromAddress.String()) + return pkgerrors.Errorf("cannot create tx attempt: specified gas price of %s is below min configured gas price of %s for key %s", gasPrice.String(), min.String(), etx.FromAddress.String()) } return nil } @@ -278,7 +278,7 @@ func validateLegacyGas(ctx context.Context, kse keySpecificEstimator, minGasPric func (c *evmTxAttemptBuilder) newSignedAttempt(ctx context.Context, etx Tx, tx *types.Transaction) (attempt TxAttempt, err error) { hash, signedTxBytes, err := c.SignTx(ctx, etx.FromAddress, tx) if err != nil { - return attempt, errors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress.String(), etx.ID) + return attempt, pkgerrors.Wrapf(err, "error using account %s to sign transaction %v", etx.FromAddress.String(), etx.ID) } attempt.State = txmgrtypes.TxAttemptInProgress @@ -308,7 +308,7 @@ func (c *evmTxAttemptBuilder) SignTx(ctx context.Context, address common.Address } rlp := new(bytes.Buffer) if err := signedTx.EncodeRLP(rlp); err != nil { - return common.Hash{}, nil, errors.Wrap(err, "SignTx failed") + return common.Hash{}, nil, pkgerrors.Wrap(err, "SignTx failed") } txHash := signedTx.Hash() return txHash, rlp.Bytes(), nil diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index e0b3cd59ce7..b1e24984c37 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -9,7 +9,7 @@ import ( "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" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -257,8 +257,8 @@ func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { func TestTxm_EvmTxAttemptBuilder_RetryableEstimatorError(t *testing.T) { est := gasmocks.NewEvmFeeEstimator(t) - est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), errors.New("fail")) - est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), errors.New("fail")) + est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), pkgerrors.New("fail")) + est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), pkgerrors.New("fail")) kst := ksmocks.NewEth(t) lggr := logger.Test(t) diff --git a/core/chains/evm/txmgr/common.go b/core/chains/evm/txmgr/common.go index d1e851f0c21..75fd3628ed5 100644 --- a/core/chains/evm/txmgr/common.go +++ b/core/chains/evm/txmgr/common.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -74,7 +74,7 @@ func batchSendTransactions( logger.Debugw(fmt.Sprintf("Batch sending transactions %v thru %v", i, j)) if err := ethClient.BatchCallContextAll(ctx, reqs[i:j]); err != nil { - return reqs, now, successfulBroadcast, errors.Wrap(err, "failed to batch send transactions") + return reqs, now, successfulBroadcast, pkgerrors.Wrap(err, "failed to batch send transactions") } successfulBroadcast = append(successfulBroadcast, ethTxIDs[i:j]...) } diff --git a/core/chains/evm/txmgr/nonce_syncer.go b/core/chains/evm/txmgr/nonce_syncer.go index 2936736b3b3..0cb52a1321e 100644 --- a/core/chains/evm/txmgr/nonce_syncer.go +++ b/core/chains/evm/txmgr/nonce_syncer.go @@ -6,7 +6,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -76,13 +76,13 @@ func NewNonceSyncer( // Calling it later is not safe and could lead to races. func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address, localNonce types.Nonce) (nonce types.Nonce, err error) { nonce, err = s.fastForwardNonceIfNecessary(ctx, addr, localNonce) - return nonce, errors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") + return nonce, pkgerrors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") } func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address, localNonce types.Nonce) (types.Nonce, error) { chainNonce, err := s.pendingNonceFromEthClient(ctx, address) if err != nil { - return localNonce, errors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") + return localNonce, pkgerrors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") } if chainNonce == 0 { return localNonce, nil @@ -102,5 +102,5 @@ func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, addres func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (types.Nonce, error) { nextNonce, err := s.client.PendingSequenceAt(ctx, account) - return nextNonce, errors.WithStack(err) + return nextNonce, pkgerrors.WithStack(err) } diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index f757b8863d1..d9a741fb3c5 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -12,7 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -32,7 +32,7 @@ func Test_NonceSyncer_Sync(t *testing.T) { ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) - ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), errors.New("something exploded")) + ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), pkgerrors.New("something exploded")) _, err := ns.Sync(testutils.Context(t), from, types.Nonce(0)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index e8c1c9e079f..7cf575e8c8d 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -177,7 +177,7 @@ func Test_EthResender_Start(t *testing.T) { })).Return(nil).Run(func(args mock.Arguments) { elems := args.Get(1).([]rpc.BatchElem) // It should update BroadcastAt even if there is an error here - elems[0].Error = errors.New("kaboom") + elems[0].Error = pkgerrors.New("kaboom") }) func() { diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index 5a5cc3dbcd4..8956f2ae626 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" @@ -53,11 +53,11 @@ func (c *CheckerFactory) BuildChecker(spec TransmitCheckerSpec) (TransmitChecker return &SimulateChecker{c.Client}, nil case TransmitCheckerTypeVRFV1: if spec.VRFCoordinatorAddress == nil { - return nil, errors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) + return nil, pkgerrors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) } coord, err := v1.NewVRFCoordinator(*spec.VRFCoordinatorAddress, c.Client) if err != nil { - return nil, errors.Wrapf(err, + return nil, pkgerrors.Wrapf(err, "failed to create VRF V1 coordinator at address %v", spec.VRFCoordinatorAddress) } return &VRFV1Checker{ @@ -66,15 +66,15 @@ func (c *CheckerFactory) BuildChecker(spec TransmitCheckerSpec) (TransmitChecker }, nil case TransmitCheckerTypeVRFV2: if spec.VRFCoordinatorAddress == nil { - return nil, errors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) + return nil, pkgerrors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) } coord, err := v2.NewVRFCoordinatorV2(*spec.VRFCoordinatorAddress, c.Client) if err != nil { - return nil, errors.Wrapf(err, + return nil, pkgerrors.Wrapf(err, "failed to create VRF V2 coordinator at address %v", spec.VRFCoordinatorAddress) } if spec.VRFRequestBlockNumber == nil { - return nil, errors.New("VRFRequestBlockNumber parameter must be non-nil") + return nil, pkgerrors.New("VRFRequestBlockNumber parameter must be non-nil") } return &VRFV2Checker{ GetCommitment: coord.GetCommitment, @@ -83,15 +83,15 @@ func (c *CheckerFactory) BuildChecker(spec TransmitCheckerSpec) (TransmitChecker }, nil case TransmitCheckerTypeVRFV2Plus: if spec.VRFCoordinatorAddress == nil { - return nil, errors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) + return nil, pkgerrors.Errorf("malformed checker, expected non-nil VRFCoordinatorAddress, got: %v", spec) } coord, err := vrf_coordinator_v2plus_interface.NewIVRFCoordinatorV2PlusInternal(*spec.VRFCoordinatorAddress, c.Client) if err != nil { - return nil, errors.Wrapf(err, + return nil, pkgerrors.Wrapf(err, "failed to create VRF V2 coordinator plus at address %v", spec.VRFCoordinatorAddress) } if spec.VRFRequestBlockNumber == nil { - return nil, errors.New("VRFRequestBlockNumber parameter must be non-nil") + return nil, pkgerrors.New("VRFRequestBlockNumber parameter must be non-nil") } return &VRFV2Checker{ GetCommitment: coord.SRequestCommitments, @@ -101,7 +101,7 @@ func (c *CheckerFactory) BuildChecker(spec TransmitCheckerSpec) (TransmitChecker case "": return NoChecker, nil default: - return nil, errors.Errorf("unrecognized checker type: %s", spec.CheckerType) + return nil, pkgerrors.Errorf("unrecognized checker type: %s", spec.CheckerType) } } @@ -150,7 +150,7 @@ func (s *SimulateChecker) Check( if jErr := evmclient.ExtractRPCErrorOrNil(err); jErr != nil { 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()) + return pkgerrors.Errorf("transaction reverted during simulation: %s", jErr.String()) } l.Warnw("Transaction simulation failed, will attempt to send anyway", "ethTxAttemptID", a.ID, "txHash", a.Hash, "err", err, "returnValue", b.String()) @@ -259,7 +259,7 @@ func (v *VRFV1Checker) Check( "ethTxID", tx.ID, "meta", tx.Meta, "reqID", reqID) - return errors.New("request already fulfilled") + return pkgerrors.New("request already fulfilled") } // Request not fulfilled return nil @@ -350,7 +350,7 @@ func (v *VRFV2Checker) Check( "ethTxID", tx.ID, "meta", tx.Meta, "vrfRequestId", vrfRequestID) - return errors.New("request already fulfilled") + return pkgerrors.New("request already fulfilled") } l.Debugw("Request not yet fulfilled", "ethTxID", tx.ID, diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index d2f668da11b..2fce9cf7aac 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -165,7 +165,7 @@ func TestTransmitCheckers(t *testing.T) { mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { return fmt.Sprintf("%s", callarg["value"]) == "0x282" // 642 - }), "latest").Return(errors.New("error")).Once() + }), "latest").Return(pkgerrors.New("error")).Once() // Non-revert errors are logged but should not prevent transmission, and do not need // to be passed to the caller @@ -221,7 +221,7 @@ func TestTransmitCheckers(t *testing.T) { Callbacks: func(opts *bind.CallOpts, reqID [32]byte) (v1.Callbacks, error) { if opts.BlockNumber.Cmp(big.NewInt(6)) != 0 { // Ensure correct logic is applied to get callbacks. - return v1.Callbacks{}, errors.New("error getting callback") + return v1.Callbacks{}, pkgerrors.New("error getting callback") } if reqID == r1 { // Request 1 is already fulfilled @@ -230,7 +230,7 @@ func TestTransmitCheckers(t *testing.T) { }, nil } else if reqID == r2 { // Request 2 errors - return v1.Callbacks{}, errors.New("error getting commitment") + return v1.Callbacks{}, pkgerrors.New("error getting commitment") } return v1.Callbacks{ SeedAndBlockNum: [32]byte{1}, @@ -277,7 +277,7 @@ func TestTransmitCheckers(t *testing.T) { t.Run("failure fetching tx receipt and block head", func(t *testing.T) { tx, attempt := txRequest(t, r1, false) - mockBatch.Return(errors.New("could not fetch")) + mockBatch.Return(pkgerrors.New("could not fetch")) err := checker.Check(ctx, log, tx, attempt) require.NoError(t, err) }) @@ -324,7 +324,7 @@ func TestTransmitCheckers(t *testing.T) { return [32]byte{}, nil } else if requestID.String() == "2" { // Request 2 errors - return [32]byte{}, errors.New("error getting commitment") + return [32]byte{}, pkgerrors.New("error getting commitment") } // All other requests are unfulfilled return [32]byte{1}, nil @@ -355,7 +355,7 @@ func TestTransmitCheckers(t *testing.T) { t.Run("can't get header", func(t *testing.T) { checker.HeadByNumber = func(ctx context.Context, n *big.Int) (*evmtypes.Head, error) { - return nil, errors.New("can't get head") + return nil, pkgerrors.New("can't get head") } tx, attempt := txRequest(t, big.NewInt(3)) require.NoError(t, checker.Check(ctx, log, tx, attempt)) diff --git a/core/chains/evm/types/internal/blocks/transactions.go b/core/chains/evm/types/internal/blocks/transactions.go index b607e2dcfd1..887a16f99d1 100644 --- a/core/chains/evm/types/internal/blocks/transactions.go +++ b/core/chains/evm/types/internal/blocks/transactions.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) type TxType uint8 @@ -22,7 +22,7 @@ func (txt *TxType) UnmarshalJSON(data []byte) error { return err } if hx > math.MaxUint8 { - return errors.Errorf("expected 'type' to fit into a single byte, got: '%s'", data) + return pkgerrors.Errorf("expected 'type' to fit into a single byte, got: '%s'", data) } *txt = TxType(hx) return nil diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 7db38fc6821..464eb901005 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/ugorji/go/codec" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" @@ -355,7 +355,7 @@ func (b Block) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } -var ErrMissingBlock = errors.New("missing block") +var ErrMissingBlock = pkgerrors.New("missing block") // UnmarshalJSON unmarshals to a Block func (b *Block) UnmarshalJSON(data []byte) error { @@ -370,12 +370,12 @@ func (b *Block) UnmarshalJSON(data []byte) error { return err } if bi.Empty() { - return errors.WithStack(ErrMissingBlock) + return pkgerrors.WithStack(ErrMissingBlock) } n, err := hexutil.DecodeBig(bi.Number) if err != nil { - return errors.Wrapf(err, "failed to decode block number while unmarshalling block, got: '%s' in '%s'", bi.Number, data) + return pkgerrors.Wrapf(err, "failed to decode block number while unmarshalling block, got: '%s' in '%s'", bi.Number, data) } *b = Block{ Number: n.Int64(), @@ -421,7 +421,7 @@ func (t *Transaction) UnmarshalJSON(data []byte) error { } if ti.Gas == nil { - return errors.Errorf("expected 'gas' to not be null, got: '%s'", data) + return pkgerrors.Errorf("expected 'gas' to not be null, got: '%s'", data) } if ti.Type == nil { tpe := LegacyTxType @@ -502,7 +502,7 @@ func unmarshalFromString(s string, f *FunctionSelector) error { } bytes := common.FromHex(s) if len(bytes) != FunctionSelectorLength { - return errors.New("function ID must be 4 bytes in length") + return pkgerrors.New("function ID must be 4 bytes in length") } f.SetBytes(bytes) } else { @@ -559,7 +559,7 @@ type UntrustedBytes []byte func (ary UntrustedBytes) SafeByteSlice(start int, end int) ([]byte, error) { if end > len(ary) || start > end || start < 0 || end < 0 { var empty []byte - return empty, errors.New("out of bounds slice access") + return empty, pkgerrors.New("out of bounds slice access") } return ary[start:end], nil } diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index f2f58c3a983..4fc986ae9d3 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -935,8 +935,8 @@ func TestBlock_UnmarshalJSON(t *testing.T) { b := new(evmtypes.Block) err := b.UnmarshalJSON([]byte("null")) assert.Error(t, err) - assert.Equal(t, errors.Cause(err), evmtypes.ErrMissingBlock) - assert.True(t, errors.Is(err, evmtypes.ErrMissingBlock)) + assert.Equal(t, pkgerrors.Cause(err), evmtypes.ErrMissingBlock) + assert.True(t, pkgerrors.Is(err, evmtypes.ErrMissingBlock)) }) t.Run("unmarshals EIP-4844 block", func(t *testing.T) { b := new(evmtypes.Block) diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index c3ad584ebbd..89739e61e1b 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/jackc/pgtype" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -143,7 +143,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { } var dec Receipt if err := json.Unmarshal(input, &dec); err != nil { - return errors.Wrap(err, "could not unmarshal receipt") + return pkgerrors.Wrap(err, "could not unmarshal receipt") } if dec.PostState != nil { r.PostState = *dec.PostState @@ -182,7 +182,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { func (r *Receipt) Scan(value interface{}) error { b, ok := value.([]byte) if !ok { - return errors.New("type assertion to []byte failed") + return pkgerrors.New("type assertion to []byte failed") } return json.Unmarshal(b, r) @@ -294,7 +294,7 @@ func (l *Log) UnmarshalJSON(input []byte) error { } var dec Log if err := json.Unmarshal(input, &dec); err != nil { - return errors.Wrap(err, "could not unmarshal log") + return pkgerrors.Wrap(err, "could not unmarshal log") } if dec.Address != nil { l.Address = *dec.Address @@ -330,20 +330,20 @@ func (a *AddressArray) Scan(src interface{}) error { baArray := pgtype.ByteaArray{} err := baArray.Scan(src) if err != nil { - return errors.Wrap(err, "Expected BYTEA[] column for AddressArray") + return pkgerrors.Wrap(err, "Expected BYTEA[] column for AddressArray") } if baArray.Status != pgtype.Present { *a = nil return nil } if len(baArray.Dimensions) > 1 { - return errors.Errorf("Expected AddressArray to be 1-dimensional. Dimensions = %v", baArray.Dimensions) + return pkgerrors.Errorf("Expected AddressArray to be 1-dimensional. Dimensions = %v", baArray.Dimensions) } for i, ba := range baArray.Elements { addr := common.Address{} if ba.Status != pgtype.Present { - return errors.Errorf("Expected all addresses in AddressArray to be non-NULL. Got AddressArray[%d] = NULL", i) + return pkgerrors.Errorf("Expected all addresses in AddressArray to be non-NULL. Got AddressArray[%d] = NULL", i) } err = addr.Scan(ba.Bytes) if err != nil { @@ -361,20 +361,20 @@ func (h *HashArray) Scan(src interface{}) error { baArray := pgtype.ByteaArray{} err := baArray.Scan(src) if err != nil { - return errors.Wrap(err, "Expected BYTEA[] column for HashArray") + return pkgerrors.Wrap(err, "Expected BYTEA[] column for HashArray") } if baArray.Status != pgtype.Present { *h = nil return nil } if len(baArray.Dimensions) > 1 { - return errors.Errorf("Expected HashArray to be 1-dimensional. Dimensions = %v", baArray.Dimensions) + return pkgerrors.Errorf("Expected HashArray to be 1-dimensional. Dimensions = %v", baArray.Dimensions) } for i, ba := range baArray.Elements { hash := common.Hash{} if ba.Status != pgtype.Present { - return errors.Errorf("Expected all hashes in HashArray to be non-NULL. Got HashArray[%d] = NULL", i) + return pkgerrors.Errorf("Expected all hashes in HashArray to be non-NULL. Got HashArray[%d] = NULL", i) } err = hash.Scan(ba.Bytes) if err != nil { diff --git a/core/chains/evm/utils/ethabi.go b/core/chains/evm/utils/ethabi.go index 61d365933d2..08dfd54f430 100644 --- a/core/chains/evm/utils/ethabi.go +++ b/core/chains/evm/utils/ethabi.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/shopspring/decimal" "github.com/tidwall/gjson" @@ -222,7 +222,7 @@ func EVMWordSignedBigInt(val *big.Int) ([]byte, error) { // a signed representation. Returns error on overflow. func EVMWordBigInt(val *big.Int) ([]byte, error) { if val.Sign() == -1 { - return nil, errors.New("Uint256 cannot be negative") + return nil, pkgerrors.New("Uint256 cannot be negative") } bytes := val.Bytes() if len(bytes) > EVMWordByteLen { diff --git a/core/chains/evm/utils/ethabi_test.go b/core/chains/evm/utils/ethabi_test.go index b99d906eae7..f28a083ff01 100644 --- a/core/chains/evm/utils/ethabi_test.go +++ b/core/chains/evm/utils/ethabi_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" @@ -636,7 +636,7 @@ func EVMTranscodeBytes(value gjson.Result) ([]byte, error) { vInt, _ := v.Int(nil) word, err := EVMWordSignedBigInt(vInt) if err != nil { - return nil, errors.Wrap(err, "while converting float to int256") + return nil, pkgerrors.Wrap(err, "while converting float to int256") } return EVMEncodeBytes(word), nil default: diff --git a/core/config/app_config.go b/core/config/app_config.go index 648939b871b..290e14dcc45 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -4,13 +4,13 @@ import ( "time" "github.com/google/uuid" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "go.uber.org/zap/zapcore" ) // nolint var ( - ErrEnvUnset = errors.New("env var unset") + ErrEnvUnset = pkgerrors.New("env var unset") ) type LogfFn func(string, ...any) diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 8b4e38b980d..919113e1d93 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -6,7 +6,7 @@ import ( "github.com/kylelemons/godebug/diff" gotoml "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -31,7 +31,7 @@ func TestDoc(t *testing.T) { var strict *gotoml.StrictMissingError if err != nil && strings.Contains(err.Error(), "undecoded keys: ") { t.Errorf("Docs contain extra fields: %v", err) - } else if errors.As(err, &strict) { + } else if pkgerrors.As(err, &strict) { t.Fatal("StrictMissingError:", strict.String()) } else { require.NoError(t, err) diff --git a/core/config/parse/parsers.go b/core/config/parse/parsers.go index 6243b74dd52..371354ba36e 100644 --- a/core/config/parse/parsers.go +++ b/core/config/parse/parsers.go @@ -10,7 +10,7 @@ import ( "time" "github.com/mitchellh/go-homedir" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "go.uber.org/zap/zapcore" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" @@ -113,7 +113,7 @@ func HomeDir(str string) (string, error) { func DatabaseURL(s string) (url.URL, error) { uri, err := url.Parse(s) if err != nil { - return url.URL{}, errors.Wrapf(err, "invalid database url %s", s) + return url.URL{}, pkgerrors.Wrapf(err, "invalid database url %s", s) } if uri.String() == "" { return *uri, nil diff --git a/core/gethwrappers/versions.go b/core/gethwrappers/versions.go index acdefd06a59..43a59ddbb75 100644 --- a/core/gethwrappers/versions.go +++ b/core/gethwrappers/versions.go @@ -9,7 +9,7 @@ import ( "sort" "strings" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "go.uber.org/multierr" ) @@ -44,11 +44,11 @@ func dbPath() (path string, err error) { func versionsDBLineReader() (*bufio.Scanner, error) { versionsDBPath, err := dbPath() if err != nil { - return nil, errors.Wrapf(err, "could not construct versions DB path") + return nil, pkgerrors.Wrapf(err, "could not construct versions DB path") } versionsDBFile, err := os.Open(versionsDBPath) if err != nil { - return nil, errors.Wrapf(err, "could not open versions database") + return nil, pkgerrors.Wrapf(err, "could not open versions database") } return bufio.NewScanner(versionsDBFile), nil @@ -66,28 +66,28 @@ func ReadVersionsDB() (*IntegratedVersion, error) { for db.Scan() { line := strings.Fields(db.Text()) if !strings.HasSuffix(line[0], ":") { - return nil, errors.Errorf( + return nil, pkgerrors.Errorf( `each line in versions.txt should start with "$TOPIC:"`) } topic := stripTrailingColon(line[0], "") if topic == "GETH_VERSION" { if len(line) != 2 { - return nil, errors.Errorf("GETH_VERSION line should contain geth "+ + return nil, pkgerrors.Errorf("GETH_VERSION line should contain geth "+ "version, and only that: %s", line) } if rv.GethVersion != "" { - return nil, errors.Errorf("more than one geth version") + return nil, pkgerrors.Errorf("more than one geth version") } rv.GethVersion = line[1] } else { // It's a wrapper from a compiler artifact if len(line) != 4 { - return nil, errors.Errorf(`"%s" should have four elements `+ + return nil, pkgerrors.Errorf(`"%s" should have four elements `+ `": "`, db.Text()) } _, alreadyExists := rv.ContractVersions[topic] if alreadyExists { - return nil, errors.Errorf(`topic "%s" already mentioned`, topic) + return nil, pkgerrors.Errorf(`topic "%s" already mentioned`, topic) } rv.ContractVersions[topic] = ContractVersion{ AbiPath: line[1], BinaryPath: line[2], Hash: line[3], @@ -102,11 +102,11 @@ var stripTrailingColon = regexp.MustCompile(":$").ReplaceAllString func WriteVersionsDB(db *IntegratedVersion) (err error) { versionsDBPath, err := dbPath() if err != nil { - return errors.Wrap(err, "could not construct path to versions DB") + return pkgerrors.Wrap(err, "could not construct path to versions DB") } f, err := os.Create(versionsDBPath) if err != nil { - return errors.Wrapf(err, "while opening %s", versionsDBPath) + return pkgerrors.Wrapf(err, "while opening %s", versionsDBPath) } defer func() { if cerr := f.Close(); cerr != nil { @@ -116,10 +116,10 @@ func WriteVersionsDB(db *IntegratedVersion) (err error) { gethLine := "GETH_VERSION: " + db.GethVersion + "\n" n, err := f.WriteString(gethLine) if err != nil { - return errors.Wrapf(err, "while recording geth version line") + return pkgerrors.Wrapf(err, "while recording geth version line") } if n != len(gethLine) { - return errors.Errorf("failed to write entire geth version line, %s", gethLine) + return pkgerrors.Errorf("failed to write entire geth version line, %s", gethLine) } var pkgNames []string for name := range db.ContractVersions { @@ -132,10 +132,10 @@ func WriteVersionsDB(db *IntegratedVersion) (err error) { vinfo.AbiPath, vinfo.BinaryPath, vinfo.Hash) n, err = f.WriteString(versionLine) if err != nil { - return errors.Wrapf(err, "while recording %s version line", name) + return pkgerrors.Wrapf(err, "while recording %s version line", name) } if n != len(versionLine) { - return errors.Errorf("failed to write entire version line %s", versionLine) + return pkgerrors.Errorf("failed to write entire version line %s", versionLine) } } return nil diff --git a/core/internal/testutils/httptest/httptest.go b/core/internal/testutils/httptest/httptest.go index 7607ca7552d..a1bd941fb02 100644 --- a/core/internal/testutils/httptest/httptest.go +++ b/core/internal/testutils/httptest/httptest.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) // NewTestHTTPClient returns a real HTTP client that may only make requests to @@ -31,7 +31,7 @@ func testDialContext(ctx context.Context, network, address string) (net.Conn, er } a := con.RemoteAddr().(*net.TCPAddr) if a != nil && !a.IP.IsLoopback() { - return nil, errors.Errorf("Test HTTP client may only dial localhost, got address: %v", a.String()) + return nil, pkgerrors.Errorf("Test HTTP client may only dial localhost, got address: %v", a.String()) } return con, err } diff --git a/core/internal/testutils/keystest/keystest.go b/core/internal/testutils/keystest/keystest.go index beb7e580f1b..850e1ad1fa0 100644 --- a/core/internal/testutils/keystest/keystest.go +++ b/core/internal/testutils/keystest/keystest.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) // NewKey pulled from geth @@ -19,7 +19,7 @@ func NewKey() (key keystore.Key, err error) { id, err := uuid.NewRandom() if err != nil { - return key, errors.Errorf("Could not create random uuid: %v", err) + return key, pkgerrors.Errorf("Could not create random uuid: %v", err) } return keystore.Key{ diff --git a/core/logger/zap.go b/core/logger/zap.go index c739a80d45a..e11458bdf8b 100644 --- a/core/logger/zap.go +++ b/core/logger/zap.go @@ -3,7 +3,7 @@ package logger import ( "os" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -76,7 +76,7 @@ func (l *zapLogger) Sync() error { return nil } var msg string - if uw := errors.Unwrap(err); uw != nil { + if uw := pkgerrors.Unwrap(err); uw != nil { msg = uw.Error() } else { msg = err.Error() diff --git a/core/sessions/localauth/orm.go b/core/sessions/localauth/orm.go index 013f719ad34..8afaf5e7fc1 100644 --- a/core/sessions/localauth/orm.go +++ b/core/sessions/localauth/orm.go @@ -7,7 +7,7 @@ import ( "time" "github.com/jmoiron/sqlx" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/auth" @@ -69,7 +69,7 @@ func (o *orm) ListUsers() (users []sessions.User, err error) { func (o *orm) findValidSession(sessionID string) (email string, err error) { if err := o.q.Get(&email, "SELECT email FROM sessions WHERE id = $1 AND last_used + $2 >= now() FOR UPDATE", sessionID, o.sessionDuration); err != nil { o.lggr.Infof("query result: %v", email) - return email, errors.Wrap(err, "no matching user for provided session token") + return email, pkgerrors.Wrap(err, "no matching user for provided session token") } return email, nil } @@ -152,12 +152,12 @@ func (o *orm) CreateSession(sr sessions.SessionRequest) (string, error) { // for MFA tokens leaking if an account has MFA tokens or not. if !constantTimeEmailCompare(strings.ToLower(sr.Email), strings.ToLower(user.Email)) { o.auditLogger.Audit(audit.AuthLoginFailedEmail, map[string]interface{}{"email": sr.Email}) - return "", errors.New("Invalid email") + return "", pkgerrors.New("Invalid email") } if !utils.CheckPasswordHash(sr.Password, user.HashedPassword) { o.auditLogger.Audit(audit.AuthLoginFailedPassword, map[string]interface{}{"email": sr.Email}) - return "", errors.New("Invalid password") + return "", pkgerrors.New("Invalid password") } // Load all valid MFA tokens associated with user's email @@ -165,7 +165,7 @@ func (o *orm) CreateSession(sr sessions.SessionRequest) (string, error) { if err != nil { // There was an error with the database query lggr.Errorf("Could not fetch user's MFA data: %v", err) - return "", errors.New("MFA Error") + return "", pkgerrors.New("MFA Error") } // No webauthn tokens registered for the current user, so normal authentication is now complete @@ -185,16 +185,16 @@ func (o *orm) CreateSession(sr sessions.SessionRequest) (string, error) { options, webauthnError := sessions.BeginWebAuthnLogin(user, uwas, sr) if webauthnError != nil { lggr.Errorf("Could not begin WebAuthn verification: %v", webauthnError) - return "", errors.New("MFA Error") + return "", pkgerrors.New("MFA Error") } j, jsonError := json.Marshal(options) if jsonError != nil { lggr.Errorf("Could not serialize WebAuthn challenge: %v", jsonError) - return "", errors.New("MFA Error") + return "", pkgerrors.New("MFA Error") } - return "", errors.New(string(j)) + return "", pkgerrors.New(string(j)) } // The user is at the final stage of logging in with MFA. We have an @@ -206,7 +206,7 @@ func (o *orm) CreateSession(sr sessions.SessionRequest) (string, error) { // The user does have WebAuthn enabled but failed the check o.auditLogger.Audit(audit.AuthLoginFailed2FA, map[string]interface{}{"email": sr.Email, "error": err}) lggr.Errorf("User sent an invalid attestation: %v", err) - return "", errors.New("MFA Error") + return "", pkgerrors.New("MFA Error") } lggr.Infof("User passed MFA authentication and login will proceed") @@ -256,13 +256,13 @@ func (o *orm) UpdateRole(email, newRole string) (sessions.User, error) { var userToEdit sessions.User if newRole == "" { - return userToEdit, errors.New("user role must be specified") + return userToEdit, pkgerrors.New("user role must be specified") } err := o.q.Transaction(func(tx pg.Queryer) error { // First, attempt to load specified user by email if err := tx.Get(&userToEdit, "SELECT * FROM users WHERE lower(email) = lower($1)", email); err != nil { - return errors.New("no matching user for provided email") + return pkgerrors.New("no matching user for provided email") } // Patch validated role @@ -275,13 +275,13 @@ func (o *orm) UpdateRole(email, newRole string) (sessions.User, error) { _, err = tx.Exec("DELETE FROM sessions WHERE email = lower($1)", email) if err != nil { o.lggr.Errorf("Failed to purge user sessions for UpdateRole", "err", err) - return errors.New("error updating API user") + return pkgerrors.New("error updating API user") } sql := "UPDATE users SET role = $1, updated_at = now() WHERE lower(email) = lower($2) RETURNING *" if err := tx.Get(&userToEdit, sql, userToEdit.Role, email); err != nil { o.lggr.Errorf("Error updating API user", "err", err) - return errors.New("error updating API user") + return pkgerrors.New("error updating API user") } return nil @@ -304,10 +304,10 @@ func (o *orm) SetPassword(user *sessions.User, newPassword string) error { func (o *orm) TestPassword(email string, password string) error { var hashedPassword string if err := o.q.Get(&hashedPassword, "SELECT hashed_password FROM users WHERE lower(email) = lower($1)", email); err != nil { - return errors.New("no matching user for provided email") + return pkgerrors.New("no matching user for provided email") } if !utils.CheckPasswordHash(password, hashedPassword) { - return errors.New("passwords don't match") + return pkgerrors.New("passwords don't match") } return nil } @@ -328,7 +328,7 @@ func (o *orm) SetAuthToken(user *sessions.User, token *auth.Token) error { salt := utils.NewSecret(utils.DefaultSecretSize) hashedSecret, err := auth.HashedSecret(token, salt) if err != nil { - return errors.Wrap(err, "user") + return pkgerrors.Wrap(err, "user") } sql := "UPDATE users SET token_salt = $1, token_key = $2, token_hashed_secret = $3, updated_at = now() WHERE email = $4 RETURNING *" return o.q.Get(user, sql, salt, token.AccessKey, hashedSecret, user.Email) diff --git a/core/sessions/session.go b/core/sessions/session.go index 90964596e9a..49f403b6a81 100644 --- a/core/sessions/session.go +++ b/core/sessions/session.go @@ -4,7 +4,7 @@ import ( "crypto/subtle" "time" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/auth" @@ -55,7 +55,7 @@ func (u *User) SetAuthToken(token *auth.Token) error { salt := utils.NewSecret(utils.DefaultSecretSize) hashedSecret, err := auth.HashedSecret(token, salt) if err != nil { - return errors.Wrap(err, "user") + return pkgerrors.Wrap(err, "user") } u.TokenSalt = null.StringFrom(salt) u.TokenKey = null.StringFrom(token.AccessKey) diff --git a/core/sessions/user.go b/core/sessions/user.go index f2e4827b922..bcedaa4b197 100644 --- a/core/sessions/user.go +++ b/core/sessions/user.go @@ -5,7 +5,7 @@ import ( "net/mail" "time" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -58,7 +58,7 @@ func NewUser(email string, plainPwd string, role UserRole) (User, error) { // ValidateEmail is the single point of logic for user email validations func ValidateEmail(email string) error { if len(email) == 0 { - return errors.New("Must enter an email") + return pkgerrors.New("Must enter an email") } _, err := mail.ParseAddress(email) return err @@ -67,10 +67,10 @@ func ValidateEmail(email string) error { // ValidateAndHashPassword is the single point of logic for user password validations func ValidateAndHashPassword(plainPwd string) (string, error) { if err := utils.VerifyPasswordComplexity(plainPwd); err != nil { - return "", errors.Wrapf(err, "password insufficiently complex:\n%s", utils.PasswordComplexityRequirements) + return "", pkgerrors.Wrapf(err, "password insufficiently complex:\n%s", utils.PasswordComplexityRequirements) } if len(plainPwd) > MaxBcryptPasswordLength { - return "", errors.Errorf("must enter a password less than %v characters", MaxBcryptPasswordLength) + return "", pkgerrors.Errorf("must enter a password less than %v characters", MaxBcryptPasswordLength) } pwd, err := utils.HashPassword(plainPwd) @@ -104,5 +104,5 @@ func GetUserRole(role string) (UserRole, error) { UserRoleRun, UserRoleView, ) - return UserRole(""), errors.New(errStr) + return UserRole(""), pkgerrors.New(errStr) } diff --git a/core/sessions/webauthn.go b/core/sessions/webauthn.go index 89e7758bc5b..c959bec08de 100644 --- a/core/sessions/webauthn.go +++ b/core/sessions/webauthn.go @@ -10,7 +10,7 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" sqlxTypes "github.com/jmoiron/sqlx/types" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" ) // WebAuthn holds the credentials for API user. @@ -93,7 +93,7 @@ func (store *WebAuthnSessionStore) FinishWebAuthnRegistration(user User, uwas [] credential, err := webAuthn.FinishRegistration(waUser, sessionData, response) if err != nil { - return nil, errors.Wrap(err, "failed to FinishRegistration") + return nil, pkgerrors.Wrap(err, "failed to FinishRegistration") } return credential, nil @@ -137,7 +137,7 @@ func FinishWebAuthnLogin(user User, uwas []WebAuthn, sr SessionRequest) error { }) if err != nil { - return errors.Wrapf(err, "failed to create webAuthn structure with RPID: %s and RPOrigin: %s", sr.WebAuthnConfig.RPID, sr.WebAuthnConfig.RPOrigin) + return pkgerrors.Wrapf(err, "failed to create webAuthn structure with RPID: %s and RPOrigin: %s", sr.WebAuthnConfig.RPID, sr.WebAuthnConfig.RPOrigin) } credential, err := protocol.ParseCredentialRequestResponseBody(strings.NewReader(sr.WebAuthnData)) @@ -272,7 +272,7 @@ func (store *WebAuthnSessionStore) take(key string) (val string, ok bool) { func (store *WebAuthnSessionStore) GetWebauthnSession(key string) (data webauthn.SessionData, err error) { assertion, ok := store.take(key) if !ok { - err = errors.New("assertion not in challenge store") + err = pkgerrors.New("assertion not in challenge store") return } err = json.Unmarshal([]byte(assertion), &data) diff --git a/core/store/migrate/migrate.go b/core/store/migrate/migrate.go index 04da4c48e92..aff3229e92a 100644 --- a/core/store/migrate/migrate.go +++ b/core/store/migrate/migrate.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/jmoiron/sqlx" - "github.com/pkg/errors" + pkgerrors "github.com/pkg/errors" "github.com/pressly/goose/v3" "gopkg.in/guregu/null.v4" @@ -62,7 +62,7 @@ func ensureMigrated(ctx context.Context, db *sql.DB, lggr logger.Logger) error { } } if !found { - return errors.New("database state is too old. Need to migrate to chainlink version 0.9.10 first before upgrading to this version. This upgrade is NOT REVERSIBLE, so it is STRONGLY RECOMMENDED that you take a database backup before continuing") + return pkgerrors.New("database state is too old. Need to migrate to chainlink version 0.9.10 first before upgrading to this version. This upgrade is NOT REVERSIBLE, so it is STRONGLY RECOMMENDED that you take a database backup before continuing") } // ensure a goose migrations table exists with it's initial v0 @@ -88,7 +88,7 @@ func ensureMigrated(ctx context.Context, db *sql.DB, lggr logger.Logger) error { id, err = strconv.ParseInt(name[:idx], 10, 64) if err == nil && id <= 0 { - return errors.New("migration IDs must be greater than zero") + return pkgerrors.New("migration IDs must be greater than zero") } } @@ -144,7 +144,7 @@ func SetMigrationENVVars(generalConfig chainlink.GeneralConfig) error { if generalConfig.EVMEnabled() { err := os.Setenv(env.EVMChainIDNotNullMigration0195, generalConfig.EVMConfigs()[0].ChainID.String()) if err != nil { - panic(errors.Wrap(err, "failed to set migrations env variables")) + panic(pkgerrors.Wrap(err, "failed to set migrations env variables")) } } return nil From e9a2dd0df8d4384056c36b76dce33fd5ff06faa2 Mon Sep 17 00:00:00 2001 From: Domino Valdano <2644901+reductionista@users.noreply.github.com> Date: Tue, 27 Feb 2024 23:53:35 -0800 Subject: [PATCH 18/20] Replace postgresql 14+ function with postgresql 12 compatible function (#12154) * Replace postgresql 14+ function with postgresql 11 compatible function * Capitalize sql keywords * Update to postgresql 12, add note about size of multicolumn index --- core/chains/evm/logpoller/orm.go | 2 +- ...poller_filters_add_topics_logs_per_block.sql | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index f61845b870f..ca14d29563f 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -128,7 +128,7 @@ func (o *DbORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { (SELECT unnest(:address_array ::::BYTEA[]) addr) a, (SELECT unnest(:event_sig_array ::::BYTEA[]) ev) e %s - ON CONFLICT (hash_record_extended((name, evm_chain_id, address, event, topic2, topic3, topic4), 0)) + ON CONFLICT (evm.f_log_poller_filter_hash(name, evm_chain_id, address, event, topic2, topic3, topic4)) DO UPDATE SET retention=:retention ::::BIGINT, max_logs_kept=:max_logs_kept ::::NUMERIC, logs_per_block=:logs_per_block ::::NUMERIC`, topicsColumns.String(), topicsSql.String()) diff --git a/core/store/migrate/migrations/0225_log_poller_filters_add_topics_logs_per_block.sql b/core/store/migrate/migrations/0225_log_poller_filters_add_topics_logs_per_block.sql index 77e3d5fbd51..90c6d4d0451 100644 --- a/core/store/migrate/migrations/0225_log_poller_filters_add_topics_logs_per_block.sql +++ b/core/store/migrate/migrations/0225_log_poller_filters_add_topics_logs_per_block.sql @@ -1,5 +1,13 @@ -- +goose Up +-- This generates a unique BIGINT for the log_poller_filters table from hashing (name, evm_chain_id, address, event, topic2, topic3, topic4). +-- Using an ordinary multi-column index on 7 columns would require a lot of extra storage space, and there are additional complications due to the topics being allowed to be NULL. +-- Note for updating this if and when we drop support for postgresql 12 & 13: hashrecordextended() can be used directly in postgresql 14, avoiding the need for a helper function. +-- The helper function is necessary only for the IMMUTABLE keyword +CREATE OR REPLACE FUNCTION evm.f_log_poller_filter_hash(name TEXT, evm_chain_id NUMERIC, address BYTEA, event BYTEA, topic2 BYTEA, topic3 BYTEA, topic4 BYTEA) + RETURNS BIGINT + LANGUAGE SQL IMMUTABLE COST 25 PARALLEL SAFE AS 'SELECT hashtextextended(textin(record_out(($1,$2,$3,$4,$5,$6,$7))), 0)'; + ALTER TABLE evm.log_poller_filters ADD COLUMN topic2 BYTEA CHECK (octet_length(topic2) = 32), ADD COLUMN topic3 BYTEA CHECK (octet_length(topic3) = 32), @@ -7,10 +15,7 @@ ALTER TABLE evm.log_poller_filters ADD COLUMN max_logs_kept BIGINT, ADD COLUMN logs_per_block BIGINT; --- Ordinary UNIQUE CONSTRAINT can't work for topics because they can be NULL. Any row with any column being NULL automatically satisfies the unique constraint (NULL != NULL) --- Using a hash of all the columns treats NULL's as the same as any other field. If we ever get to a point where we can require postgresql >= 15 then this can --- be fixed by using UNIQUE CONSTRAINT NULLS NOT DISTINCT which treats NULL's as if they were ordinary values (NULL == NULL) -CREATE UNIQUE INDEX evm_log_poller_filters_name_chain_address_event_topics_key ON evm.log_poller_filters (hash_record_extended((name, evm_chain_id, address, event, topic2, topic3, topic4), 0)); +CREATE UNIQUE INDEX log_poller_filters_hash_key ON evm.log_poller_filters (evm.f_log_poller_filter_hash(name, evm_chain_id, address, event, topic2, topic3, topic4)); ALTER TABLE evm.log_poller_filters DROP CONSTRAINT evm_log_poller_filters_name_evm_chain_id_address_event_key; @@ -19,7 +24,7 @@ ALTER TABLE evm.log_poller_filters ALTER TABLE evm.log_poller_filters ADD CONSTRAINT evm_log_poller_filters_name_evm_chain_id_address_event_key UNIQUE (name, evm_chain_id, address, event); -DROP INDEX IF EXISTS evm_log_poller_filters_name_chain_address_event_topics_key; +DROP INDEX IF EXISTS log_poller_filters_hash_key; ALTER TABLE evm.log_poller_filters DROP COLUMN topic2, @@ -27,3 +32,5 @@ ALTER TABLE evm.log_poller_filters DROP COLUMN topic4, DROP COLUMN max_logs_kept, DROP COLUMN logs_per_block; + +DROP FUNCTION IF EXISTS evm.f_log_poller_filter_hash(TEXT, NUMERIC, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA); From aa22ad5cf1a7165a07183691525da27e3696eaed Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Wed, 28 Feb 2024 09:05:10 +0100 Subject: [PATCH 19/20] CCIP-1496 Delete expired logs by the block_timestamp (#12040) * Removing created_at index * SonarQube fix Post rebase fix Added debug log --- core/chains/evm/logpoller/log_poller.go | 1 + core/chains/evm/logpoller/orm.go | 4 +- core/chains/evm/logpoller/orm_test.go | 152 +++++++++--------- .../migrations/0226_log_poller_index_drop.sql | 5 + 4 files changed, 88 insertions(+), 74 deletions(-) create mode 100644 core/store/migrate/migrations/0226_log_poller_index_drop.sql diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index a19bbfda7f1..b1d00206130 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -916,6 +916,7 @@ func (lp *logPoller) latestBlocks(ctx context.Context) (*evmtypes.Head, int64, e } latest := blocks[0] finalized := blocks[1] + lp.lggr.Debugw("Latest blocks read from chain", "latest", latest.Number, "finalized", finalized.Number) return latest, finalized.Number, nil } diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index ca14d29563f..777cf3546cb 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -309,7 +309,7 @@ func (o *DbORM) DeleteExpiredLogs(limit int64, qopts ...pg.QOpt) (int64, error) GROUP BY evm_chain_id,address, event HAVING NOT 0 = ANY(ARRAY_AGG(retention)) ) 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) + AND l.block_timestamp <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')`, // retention is in nanoseconds (time.Duration aka BIGINT) ubig.New(o.chainID)) } @@ -397,7 +397,7 @@ func (o *DbORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { WHERE evm_chain_id = :evm_chain_id AND block_number >= :start_block AND block_number <= :end_block - ORDER BY (block_number, log_index, created_at)`, args) + ORDER BY (block_number, log_index)`, args) if err != nil { return nil, err } diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 655a7295dab..a9f39a7ac4a 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -222,92 +222,100 @@ func TestORM(t *testing.T) { topic2 := common.HexToHash("0x1600") require.NoError(t, o1.InsertLogs([]logpoller.Log{ { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 1, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(10), - EventSig: topic, - Topics: [][]byte{topic[:]}, - Address: common.HexToAddress("0x1234"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 1, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(10), + EventSig: topic, + Topics: [][]byte{topic[:]}, + Address: common.HexToAddress("0x1234"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 2, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(11), - EventSig: topic, - Topics: [][]byte{topic[:]}, - Address: common.HexToAddress("0x1234"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 2, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(11), + EventSig: topic, + Topics: [][]byte{topic[:]}, + Address: common.HexToAddress("0x1234"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 3, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(12), - EventSig: topic, - Topics: [][]byte{topic[:]}, - Address: common.HexToAddress("0x1235"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 3, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(12), + EventSig: topic, + Topics: [][]byte{topic[:]}, + Address: common.HexToAddress("0x1235"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 4, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(13), - EventSig: topic, - Topics: [][]byte{topic[:]}, - Address: common.HexToAddress("0x1235"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 4, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(13), + EventSig: topic, + Topics: [][]byte{topic[:]}, + Address: common.HexToAddress("0x1235"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 5, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(14), - EventSig: topic2, - Topics: [][]byte{topic2[:]}, - Address: common.HexToAddress("0x1234"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello2"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 5, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(14), + EventSig: topic2, + Topics: [][]byte{topic2[:]}, + Address: common.HexToAddress("0x1234"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello2"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 6, - BlockHash: common.HexToHash("0x1234"), - BlockNumber: int64(15), - EventSig: topic2, - Topics: [][]byte{topic2[:]}, - Address: common.HexToAddress("0x1235"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello2"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 6, + BlockHash: common.HexToHash("0x1234"), + BlockNumber: int64(15), + EventSig: topic2, + Topics: [][]byte{topic2[:]}, + Address: common.HexToAddress("0x1235"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello2"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 7, - BlockHash: common.HexToHash("0x1237"), - BlockNumber: int64(16), - EventSig: topic, - Topics: [][]byte{topic[:]}, - Address: common.HexToAddress("0x1236"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello short retention"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 7, + BlockHash: common.HexToHash("0x1237"), + BlockNumber: int64(16), + EventSig: topic, + Topics: [][]byte{topic[:]}, + Address: common.HexToAddress("0x1236"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello short retention"), + BlockTimestamp: time.Now(), }, { - EvmChainId: ubig.New(th.ChainID), - LogIndex: 8, - BlockHash: common.HexToHash("0x1238"), - BlockNumber: int64(17), - EventSig: topic2, - Topics: [][]byte{topic2[:]}, - Address: common.HexToAddress("0x1236"), - TxHash: common.HexToHash("0x1888"), - Data: []byte("hello2 long retention"), + EvmChainId: ubig.New(th.ChainID), + LogIndex: 8, + BlockHash: common.HexToHash("0x1238"), + BlockNumber: int64(17), + EventSig: topic2, + Topics: [][]byte{topic2[:]}, + Address: common.HexToAddress("0x1236"), + TxHash: common.HexToHash("0x1888"), + Data: []byte("hello2 long retention"), + BlockTimestamp: time.Now(), }, })) diff --git a/core/store/migrate/migrations/0226_log_poller_index_drop.sql b/core/store/migrate/migrations/0226_log_poller_index_drop.sql new file mode 100644 index 00000000000..f20fd00aaa2 --- /dev/null +++ b/core/store/migrate/migrations/0226_log_poller_index_drop.sql @@ -0,0 +1,5 @@ +-- +goose Up +DROP INDEX evm.evm_logs_idx_created_at; + +-- +goose Down +CREATE INDEX evm_logs_idx_created_at ON evm.logs (created_at); From 24c3718de8d3d392f232384a8ea8dc702f5bb84b Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Wed, 28 Feb 2024 02:38:27 -0800 Subject: [PATCH 20/20] [KS-55] Extend demo Engine to two targets (#12151) Additionally handle requests in separate goroutines, as they can be relatively long-lived. --- core/services/workflows/engine.go | 142 ++++++++++++++++--------- core/services/workflows/engine_test.go | 24 ++++- 2 files changed, 109 insertions(+), 57 deletions(-) diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 01d1326e072..8985f9d1599 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -2,6 +2,7 @@ package workflows import ( "context" + "errors" "fmt" "time" @@ -31,13 +32,17 @@ type Engine struct { consensusType string consensusConfig *values.Map consensus capabilities.ConsensusCapability - targetType string - targetConfig *values.Map - target capabilities.TargetCapability + targets []target callbackCh chan capabilities.CapabilityResponse cancel func() } +type target struct { + typeStr string + config *values.Map + capability capabilities.TargetCapability +} + func (e *Engine) Start(ctx context.Context) error { return e.StartOnce("Engine", func() error { // create a new context, since the one passed in via Start is short-lived. @@ -70,12 +75,18 @@ LOOP: e.logger.Errorf("failed to get consensus capability: %s, retrying in %d seconds", err, retrySec) break } - e.target, err = e.registry.GetTarget(ctx, e.targetType) - if err != nil { - e.logger.Errorf("failed to get target capability: %s, retrying in %d seconds", err, retrySec) - break + failed := false + for i := range e.targets { + e.targets[i].capability, err = e.registry.GetTarget(ctx, e.targets[i].typeStr) + if err != nil { + e.logger.Errorf("failed to get target capability: %s, retrying in %d seconds", err, retrySec) + failed = true + break + } + } + if !failed { + break LOOP } - break LOOP } } @@ -130,50 +141,25 @@ func (e *Engine) triggerHandlerLoop(ctx context.Context) { case <-ctx.Done(): return case resp := <-e.callbackCh: - err := e.handleExecution(ctx, resp) - if err != nil { - e.logger.Error("error executing event %+v: %w", resp, err) - } + go e.handleExecution(ctx, resp) } } } -func (e *Engine) handleExecution(ctx context.Context, event capabilities.CapabilityResponse) error { +func (e *Engine) handleExecution(ctx context.Context, event capabilities.CapabilityResponse) { e.logger.Debugw("executing on a trigger event", "event", event) - results, err := e.handleConsensus(ctx, event) + result, err := e.handleConsensus(ctx, event) if err != nil { - return err - } - if len(results.Underlying) == 0 { - return fmt.Errorf("consensus returned no reports") + e.logger.Errorf("error in handleConsensus %v", err) + return } - if len(results.Underlying) > 1 { - e.logger.Debugw("consensus returned more than one report") - } - - // we're expecting exactly one report - _, err = e.handleTarget(ctx, results.Underlying[0]) - return err -} - -func (e *Engine) handleTarget(ctx context.Context, resp values.Value) (*values.List, error) { - e.logger.Debugw("handle target") - inputs := map[string]values.Value{ - "report": resp, - } - - tr := capabilities.CapabilityRequest{ - Inputs: &values.Map{Underlying: inputs}, - Config: e.targetConfig, - Metadata: capabilities.RequestMetadata{ - WorkflowID: mockedWorkflowID, - WorkflowExecutionID: mockedExecutionID, - }, + err = e.handleTargets(ctx, result) + if err != nil { + e.logger.Error("error in handleTargets %v", err) } - return capabilities.ExecuteSync(ctx, e.target, tr) } -func (e *Engine) handleConsensus(ctx context.Context, event capabilities.CapabilityResponse) (*values.List, error) { +func (e *Engine) handleConsensus(ctx context.Context, event capabilities.CapabilityResponse) (values.Value, error) { e.logger.Debugw("running consensus", "event", event) cr := capabilities.CapabilityRequest{ Metadata: capabilities.RequestMetadata{ @@ -190,7 +176,45 @@ func (e *Engine) handleConsensus(ctx context.Context, event capabilities.Capabil }, Config: e.consensusConfig, } - return capabilities.ExecuteSync(ctx, e.consensus, cr) + chReports := make(chan capabilities.CapabilityResponse, 10) + newCtx, cancel := context.WithCancel(ctx) + defer cancel() + err := e.consensus.Execute(newCtx, chReports, cr) + if err != nil { + return nil, err + } + select { + case resp := <-chReports: + if resp.Err != nil { + return nil, resp.Err + } + return resp.Value, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +func (e *Engine) handleTargets(ctx context.Context, resp values.Value) error { + e.logger.Debugw("handle targets") + inputs := map[string]values.Value{ + "report": resp, + } + + var combinedErr error + for _, t := range e.targets { + e.logger.Debugw("sending to target", "target", t.typeStr, "inputs", inputs) + tr := capabilities.CapabilityRequest{ + Inputs: &values.Map{Underlying: inputs}, + Config: t.config, + Metadata: capabilities.RequestMetadata{ + WorkflowID: mockedWorkflowID, + WorkflowExecutionID: mockedExecutionID, + }, + } + _, err := capabilities.ExecuteSync(ctx, t.capability, tr) + combinedErr = errors.Join(combinedErr, err) + } + return combinedErr } func (e *Engine) Close() error { @@ -227,7 +251,9 @@ func NewEngine(lggr logger.Logger, registry types.CapabilitiesRegistry) (engine engine.triggerConfig, err = values.NewMap( map[string]any{ "feedlist": []any{ - 123, 456, 789, // ETHUSD, LINKUSD, USDBTC + "0x1111111111111111111100000000000000000000000000000000000000000000", // ETHUSD + "0x2222222222222222222200000000000000000000000000000000000000000000", // LINKUSD + "0x3333333333333333333300000000000000000000000000000000000000000000", // BTCUSD }, }, ) @@ -242,18 +268,18 @@ func NewEngine(lggr logger.Logger, registry types.CapabilitiesRegistry) (engine "aggregation_config": map[string]any{ // ETHUSD "0x1111111111111111111100000000000000000000000000000000000000000000": map[string]any{ - "deviation": decimal.NewFromFloat(0.003), - "heartbeat": 24, + "deviation": decimal.NewFromFloat(0.001), + "heartbeat": 1800, }, // LINKUSD "0x2222222222222222222200000000000000000000000000000000000000000000": map[string]any{ "deviation": decimal.NewFromFloat(0.001), - "heartbeat": 24, + "heartbeat": 1800, }, // BTCUSD "0x3333333333333333333300000000000000000000000000000000000000000000": map[string]any{ - "deviation": decimal.NewFromFloat(0.002), - "heartbeat": 6, + "deviation": decimal.NewFromFloat(0.001), + "heartbeat": 1800, }, }, "encoder": "EVM", @@ -265,10 +291,20 @@ func NewEngine(lggr logger.Logger, registry types.CapabilitiesRegistry) (engine return nil, err } - // Target - engine.targetType = "write_polygon-testnet-mumbai" - engine.targetConfig, err = values.NewMap(map[string]any{ - "address": "0xaabbcc", + // Targets + engine.targets = make([]target, 2) + engine.targets[0].typeStr = "write_polygon-testnet-mumbai" + engine.targets[0].config, err = values.NewMap(map[string]any{ + "address": "0x3F3554832c636721F1fD1822Ccca0354576741Ef", + "params": []any{"$(report)"}, + "abi": "receive(report bytes)", + }) + if err != nil { + return nil, err + } + engine.targets[1].typeStr = "write_ethereum-testnet-sepolia" + engine.targets[1].config, err = values.NewMap(map[string]any{ + "address": "0x54e220867af6683aE6DcBF535B4f952cB5116510", "params": []any{"$(report)"}, "abi": "receive(report bytes)", }) diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index aa84dc29cc9..e63264c789f 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -95,22 +95,37 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { ) require.NoError(t, reg.Add(ctx, consensus)) - target := newMockCapability( + target1 := newMockCapability( capabilities.MustNewCapabilityInfo( "write_polygon-testnet-mumbai", capabilities.CapabilityTypeTarget, - "a write capability targeting polygon mainnet", + "a write capability targeting polygon mumbai testnet", "v1.0.0", ), func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + list := req.Inputs.Underlying["report"].(*values.List) + return capabilities.CapabilityResponse{ + Value: list.Underlying[0], + }, nil + }, + ) + require.NoError(t, reg.Add(ctx, target1)) + target2 := newMockCapability( + capabilities.MustNewCapabilityInfo( + "write_ethereum-testnet-sepolia", + capabilities.CapabilityTypeTarget, + "a write capability targeting ethereum sepolia testnet", + "v1.0.0", + ), + func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { list := req.Inputs.Underlying["report"].(*values.List) return capabilities.CapabilityResponse{ Value: list.Underlying[0], }, nil }, ) - require.NoError(t, reg.Add(ctx, target)) + require.NoError(t, reg.Add(ctx, target2)) lggr := logger.TestLogger(t) eng, err := NewEngine(lggr, reg) @@ -130,5 +145,6 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { err = eng.Start(ctx) require.NoError(t, err) defer eng.Close() - assert.Equal(t, cr, <-target.response) + assert.Equal(t, cr, <-target1.response) + assert.Equal(t, cr, <-target2.response) }