diff --git a/.changeset/afraid-cups-scream.md b/.changeset/afraid-cups-scream.md deleted file mode 100644 index 37226b86555..00000000000 --- a/.changeset/afraid-cups-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added zkSync L1 GasPrice calculation diff --git a/.changeset/blue-phones-rest.md b/.changeset/blue-phones-rest.md deleted file mode 100644 index 4a427c78351..00000000000 --- a/.changeset/blue-phones-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal Use audited version of OCR2Base.sol in OCR3Capability.sol diff --git a/.changeset/bright-crabs-live.md b/.changeset/bright-crabs-live.md new file mode 100644 index 00000000000..7e21431ee24 --- /dev/null +++ b/.changeset/bright-crabs-live.md @@ -0,0 +1,7 @@ +--- +"chainlink": minor +--- + +Remove ocr2vrf + +#removed all ocr2vrf and dkg OCR2 plugin materials. \ No newline at end of file diff --git a/.changeset/chilled-panthers-joke.md b/.changeset/chilled-panthers-joke.md deleted file mode 100644 index 77dc4817714..00000000000 --- a/.changeset/chilled-panthers-joke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal bump `chainlink-common` version to commit 6d926be950a6f6ca289a84edad938d4eef2ee337. diff --git a/.changeset/curly-crabs-doubt.md b/.changeset/curly-crabs-doubt.md deleted file mode 100644 index 0408383bd03..00000000000 --- a/.changeset/curly-crabs-doubt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal diff --git a/.changeset/curly-zebras-agree.md b/.changeset/curly-zebras-agree.md new file mode 100644 index 00000000000..a57b379d2a3 --- /dev/null +++ b/.changeset/curly-zebras-agree.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#added support for EIP-1559 transactions for Scroll diff --git a/.changeset/eleven-buckets-search.md b/.changeset/eleven-buckets-search.md deleted file mode 100644 index 6c68fbcfdcc..00000000000 --- a/.changeset/eleven-buckets-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Add Log Poller support to Chain Reader through setting them in config. All filters should be part of the contract wide filter unless an event needs specific polling configuration, which can be set on a per event basis.. diff --git a/.changeset/fair-buttons-judge.md b/.changeset/fair-buttons-judge.md deleted file mode 100644 index 7aacd89787a..00000000000 --- a/.changeset/fair-buttons-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal Bumped `chainlink-common` package version to commit `1fb0b48758af25d689b6957ebfb76598c9fb27ea`. diff --git a/.changeset/fluffy-ghosts-sneeze.md b/.changeset/fluffy-ghosts-sneeze.md new file mode 100644 index 00000000000..48503995c23 --- /dev/null +++ b/.changeset/fluffy-ghosts-sneeze.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Dequeue minimum guaranteed upkeeps as a priority #changed diff --git a/.changeset/funny-snails-shake.md b/.changeset/funny-snails-shake.md deleted file mode 100644 index dad6c90872b..00000000000 --- a/.changeset/funny-snails-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Added API for products to query a transaction's status in the TXM #internal diff --git a/.changeset/fuzzy-frogs-live.md b/.changeset/fuzzy-frogs-live.md deleted file mode 100644 index 58a9ffd2288..00000000000 --- a/.changeset/fuzzy-frogs-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#added EVM implementation of GetFeeComponents function for ChainWriter diff --git a/.changeset/giant-pumpkins-return.md b/.changeset/giant-pumpkins-return.md deleted file mode 100644 index c908db198f7..00000000000 --- a/.changeset/giant-pumpkins-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal bumped chainlink-common version to commit 1eff5dedc9857ed8811186dd2996603942dc1107 diff --git a/.changeset/happy-fans-enjoy.md b/.changeset/happy-fans-enjoy.md deleted file mode 100644 index a9e878719d5..00000000000 --- a/.changeset/happy-fans-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#db_update ccip capability specs migration diff --git a/.changeset/healthy-plants-guess.md b/.changeset/healthy-plants-guess.md deleted file mode 100644 index 6ec74b5a040..00000000000 --- a/.changeset/healthy-plants-guess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal removed HistoryDepth to FinalityDepth validation diff --git a/.changeset/honest-avocados-heal.md b/.changeset/honest-avocados-heal.md deleted file mode 100644 index a28c08fde84..00000000000 --- a/.changeset/honest-avocados-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -add test for v23 #added diff --git a/.changeset/lemon-buttons-raise.md b/.changeset/lemon-buttons-raise.md deleted file mode 100644 index 0408383bd03..00000000000 --- a/.changeset/lemon-buttons-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal diff --git a/.changeset/metal-glasses-count.md b/.changeset/metal-glasses-count.md deleted file mode 100644 index 0408383bd03..00000000000 --- a/.changeset/metal-glasses-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal diff --git a/.changeset/ninety-zebras-hammer.md b/.changeset/ninety-zebras-hammer.md deleted file mode 100644 index 0408383bd03..00000000000 --- a/.changeset/ninety-zebras-hammer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal diff --git a/.changeset/pink-ants-reply.md b/.changeset/pink-ants-reply.md deleted file mode 100644 index fab4ef31f7f..00000000000 --- a/.changeset/pink-ants-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal remove shared secret from transmission schedule diff --git a/.changeset/pretty-dancers-pull.md b/.changeset/pretty-dancers-pull.md deleted file mode 100644 index af8ec9db0c8..00000000000 --- a/.changeset/pretty-dancers-pull.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#changed Expand EVM implementation compatibility pipeline diff --git a/.changeset/purple-poets-film.md b/.changeset/purple-poets-film.md deleted file mode 100644 index cc858c72f0f..00000000000 --- a/.changeset/purple-poets-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Implemented the `GetTransactionStatus` method on the EVM implementation of the `ChainWriter`. diff --git a/.changeset/rare-carpets-cry.md b/.changeset/rare-carpets-cry.md deleted file mode 100644 index f096d31885c..00000000000 --- a/.changeset/rare-carpets-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal capability dispatcher threading and context usage diff --git a/.changeset/metal-cars-report.md b/.changeset/red-meals-mix.md similarity index 100% rename from .changeset/metal-cars-report.md rename to .changeset/red-meals-mix.md diff --git a/.changeset/rotten-emus-work.md b/.changeset/rotten-emus-work.md deleted file mode 100644 index ecf5ee0b9f5..00000000000 --- a/.changeset/rotten-emus-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal fixed a bug where we weren't sending the value param to the txm diff --git a/.changeset/shaggy-ears-share.md b/.changeset/shaggy-ears-share.md deleted file mode 100644 index 5946faf03cf..00000000000 --- a/.changeset/shaggy-ears-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Add RegistrySyncer diff --git a/.changeset/shiny-poems-juggle.md b/.changeset/shiny-poems-juggle.md deleted file mode 100644 index 32fc2069ee7..00000000000 --- a/.changeset/shiny-poems-juggle.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"chainlink": minor ---- - -#changed Refactored the BlockHistoryEstimator check to prevent excessively bumping transactions. Check no longer waits for CheckInclusionBlocks to pass before assessing an attempt. -#bugfix Fixed a bug that would use the oldest blocks in the cached history instead of the latest to perform gas estimations. diff --git a/.changeset/shy-deers-hope.md b/.changeset/shy-deers-hope.md deleted file mode 100644 index 0408383bd03..00000000000 --- a/.changeset/shy-deers-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal diff --git a/.changeset/sour-pigs-develop.md b/.changeset/sour-pigs-develop.md deleted file mode 100644 index 5737b20601f..00000000000 --- a/.changeset/sour-pigs-develop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal remote target wait until initiated threads exit on close diff --git a/.changeset/stupid-poems-glow.md b/.changeset/stupid-poems-glow.md deleted file mode 100644 index bdd8acc66d5..00000000000 --- a/.changeset/stupid-poems-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal rework operator_ui installer diff --git a/.changeset/tall-walls-agree.md b/.changeset/tall-walls-agree.md deleted file mode 100644 index 6f1f5505b64..00000000000 --- a/.changeset/tall-walls-agree.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal upgrade keystone contracts to 0.8.24 diff --git a/.changeset/ten-falcons-suffer.md b/.changeset/ten-falcons-suffer.md deleted file mode 100644 index e4476b10457..00000000000 --- a/.changeset/ten-falcons-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -move v23 contracts #bugfix diff --git a/.changeset/tender-carpets-cry.md b/.changeset/tender-carpets-cry.md deleted file mode 100644 index 075f769ce00..00000000000 --- a/.changeset/tender-carpets-cry.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"chainlink": patch ---- - -Add new relayer type "dummy" for testing. - -#added diff --git a/.changeset/thick-lemons-beam.md b/.changeset/thick-lemons-beam.md deleted file mode 100644 index 0ce6e04780e..00000000000 --- a/.changeset/thick-lemons-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Add script to provision capability registry diff --git a/.changeset/thick-moles-travel.md b/.changeset/thick-moles-travel.md deleted file mode 100644 index 45559e47154..00000000000 --- a/.changeset/thick-moles-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal moves workflow name and owner to the yaml spec diff --git a/.changeset/tiny-camels-flow.md b/.changeset/tiny-camels-flow.md deleted file mode 100644 index 3271bbb4a39..00000000000 --- a/.changeset/tiny-camels-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#bugfix fixed ureachable code bug which could result in stuck txns diff --git a/.changeset/unlucky-pillows-fly.md b/.changeset/unlucky-pillows-fly.md deleted file mode 100644 index c8f690eda19..00000000000 --- a/.changeset/unlucky-pillows-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -add events, add getter and add comments #bugfix diff --git a/.changeset/warm-cobras-poke.md b/.changeset/warm-cobras-poke.md deleted file mode 100644 index 0bfb1dd44b4..00000000000 --- a/.changeset/warm-cobras-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#updated Fix verb formatting in the log outputs. diff --git a/.changeset/wise-wasps-drum.md b/.changeset/wise-wasps-drum.md deleted file mode 100644 index 0a4a6eaf665..00000000000 --- a/.changeset/wise-wasps-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal Add loggercheck linter to verify that \*w logging methods have even number of args. diff --git a/.changeset/young-parrots-peel.md b/.changeset/young-parrots-peel.md deleted file mode 100644 index a7b696d14ff..00000000000 --- a/.changeset/young-parrots-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Add registry syncer package #internal diff --git a/CODEOWNERS b/.github/CODEOWNERS similarity index 95% rename from CODEOWNERS rename to .github/CODEOWNERS index 5b80a90b27a..c7eb22991b5 100644 --- a/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,8 +2,8 @@ # 1. Per Github docs: "Order is important; the last matching pattern takes the most precedence." # Please define less specific codeowner paths before more specific codeowner paths in order for the more specific rule to have priority -# Core -/core @smartcontractkit/foundations +# Root +* @smartcontractkit/foundations # Chains /common @smartcontractkit/bix-framework @@ -34,8 +34,6 @@ /core/services/pipeline/task.vrf.go @smartcontractkit/vrf-team /core/services/pipeline/task.vrfv2.go @smartcontractkit/vrf-team /core/services/pipeline/task.vrfv2plus.go @smartcontractkit/vrf-team -/core/services/ocr2/plugins/dkg @smartcontractkit/vrf-team -/core/services/ocr2/plugins/ocr2vrf @smartcontractkit/vrf-team # Keeper/Automation-related services /core/services/keeper @smartcontractkit/keepers @@ -111,8 +109,8 @@ contracts/scripts/requirements.txt @smartcontractkit/prodsec-public .nvmrc @smartcontractkit/prodsec-public contracts/package.json @smartcontractkit/prodsec-public contracts/pnpm.lock @smartcontractkit/prodsec-public -go.mod @smartcontractkit/prodsec-public -go.sum @smartcontractkit/prodsec-public +go.mod @smartcontractkit/prodsec-public @smartcontractkit/releng @smartcontractkit/foundations +go.sum @smartcontractkit/prodsec-public @smartcontractkit/releng @smartcontractkit/foundations integration-tests/go.mod @smartcontractkit/prodsec-public integration-tests/go.sum @smartcontractkit/prodsec-public flake.nix @smartcontractkit/prodsec-public diff --git a/.github/actions/split-tests/.npmrc b/.github/actions/split-tests/.npmrc deleted file mode 100644 index 4c2f52b3be7..00000000000 --- a/.github/actions/split-tests/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -auto-install-peers=true -strict-peer-dependencies=false diff --git a/.github/actions/split-tests/action.yaml b/.github/actions/split-tests/action.yaml deleted file mode 100644 index d11f0bcbc3a..00000000000 --- a/.github/actions/split-tests/action.yaml +++ /dev/null @@ -1,35 +0,0 @@ -name: Test Spliting -description: Split tests -inputs: - config: - required: true - description: The path to the splitting config -outputs: - splits: - description: The generated test splits - value: ${{ steps.split.outputs.splits }} -runs: - using: composite - steps: - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: ^8.0.0 - - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: "16" - cache: "pnpm" - cache-dependency-path: "./.github/actions/split-tests/pnpm-lock.yaml" - - - name: Install dependencies - shell: bash - run: pnpm i --prod - working-directory: "./.github/actions/split-tests" - - - name: Run test spliter - id: split - shell: bash - run: pnpm start - env: - CONFIG: ${{ inputs.config }} - working-directory: "./.github/actions/split-tests" diff --git a/.github/actions/split-tests/jest.config.js b/.github/actions/split-tests/jest.config.js deleted file mode 100644 index 7b3dcf296ff..00000000000 --- a/.github/actions/split-tests/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -const jestConfig = { - preset: "ts-jest/presets/default-esm", - resolver: "/mjs-resolver.ts", - transform: { - "^.+\\.mts?$": [ - "ts-jest", - { - useESM: true, - }, - ], - }, - testEnvironment: "node", -}; -export default jestConfig; diff --git a/.github/actions/split-tests/mjs-resolver.ts b/.github/actions/split-tests/mjs-resolver.ts deleted file mode 100644 index 92c66f7b6ca..00000000000 --- a/.github/actions/split-tests/mjs-resolver.ts +++ /dev/null @@ -1,15 +0,0 @@ -const mjsResolver = (path, options) => { - const mjsExtRegex = /\.mjs$/i; - const resolver = options.defaultResolver; - if (mjsExtRegex.test(path)) { - try { - return resolver(path.replace(mjsExtRegex, ".mts"), options); - } catch { - // use default resolver - } - } - - return resolver(path, options); -}; - -module.exports = mjsResolver; diff --git a/.github/actions/split-tests/package.json b/.github/actions/split-tests/package.json deleted file mode 100644 index 10a71c0b351..00000000000 --- a/.github/actions/split-tests/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "shard-packages", - "version": "1.0.0", - "description": "", - "type": "module", - "main": "index.js", - "scripts": { - "start": "ts-node -T --esm ./src/index.mts", - "test": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js" - }, - "keywords": [], - "author": "", - "license": "MIT", - "engines": { - "node": "^16.0.0", - "pnpm": "^8.0.0" - }, - "dependencies": { - "@actions/core": "^1.10.1", - "ts-node": "^10.9.2", - "zx": "^7.2.3" - }, - "devDependencies": { - "@types/jest": "^29.5.12", - "@types/node": "^18.19.32", - "jest": "^29.7.0", - "ts-jest": "^29.1.2", - "typescript": "^5.4.5" - } -} diff --git a/.github/actions/split-tests/pnpm-lock.yaml b/.github/actions/split-tests/pnpm-lock.yaml deleted file mode 100644 index 730971e0c63..00000000000 --- a/.github/actions/split-tests/pnpm-lock.yaml +++ /dev/null @@ -1,3071 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@actions/core': - specifier: ^1.10.1 - version: 1.10.1 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@18.19.32)(typescript@5.4.5) - zx: - specifier: ^7.2.3 - version: 7.2.3 - -devDependencies: - '@types/jest': - specifier: ^29.5.12 - version: 29.5.12 - '@types/node': - specifier: ^18.19.32 - version: 18.19.32 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - ts-jest: - specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.19.3)(jest@29.7.0)(typescript@5.4.5) - typescript: - specifier: ^5.4.5 - version: 5.4.5 - -packages: - - /@actions/core@1.10.1: - resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==} - dependencies: - '@actions/http-client': 2.0.1 - uuid: 8.3.2 - dev: false - - /@actions/http-client@2.0.1: - resolution: {integrity: sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==} - dependencies: - tunnel: 0.0.6 - dev: false - - /@ampproject/remapping@2.2.0: - resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.25 - dev: true - - /@babel/code-frame@7.18.6: - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.18.6 - dev: true - - /@babel/code-frame@7.24.2: - resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.24.2 - picocolors: 1.0.0 - dev: true - - /@babel/compat-data@7.19.3: - resolution: {integrity: sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/compat-data@7.24.4: - resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.19.3: - resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.3 - '@babel/helper-compilation-targets': 7.19.3(@babel/core@7.19.3) - '@babel/helper-module-transforms': 7.19.0 - '@babel/helpers': 7.19.0 - '@babel/parser': 7.19.3 - '@babel/template': 7.18.10 - '@babel/traverse': 7.24.1 - '@babel/types': 7.19.3 - convert-source-map: 1.8.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/core@7.24.4: - resolution: {integrity: sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 - convert-source-map: 2.0.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.19.3: - resolution: {integrity: sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.19.3 - '@jridgewell/gen-mapping': 0.3.2 - jsesc: 2.5.2 - dev: true - - /@babel/generator@7.24.4: - resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 - dev: true - - /@babel/helper-compilation-targets@7.19.3(@babel/core@7.19.3): - resolution: {integrity: sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.19.3 - '@babel/core': 7.19.3 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.4 - semver: 6.3.0 - dev: true - - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.24.4 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.23.0 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-environment-visitor@7.18.9: - resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-module-imports@7.18.6: - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@babel/helper-module-imports@7.24.3: - resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-module-transforms@7.19.0: - resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.18.10 - '@babel/traverse': 7.24.1 - '@babel/types': 7.19.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.4): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.24.4 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.24.3 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/helper-plugin-utils@7.19.0: - resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-simple-access@7.18.6: - resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-split-export-declaration@7.18.6: - resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-string-parser@7.18.10: - resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-string-parser@7.24.1: - resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.19.1: - resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-option@7.18.6: - resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.19.0: - resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.18.10 - '@babel/traverse': 7.24.1 - '@babel/types': 7.19.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helpers@7.24.4: - resolution: {integrity: sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.19.1 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@babel/highlight@7.24.2: - resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.0 - dev: true - - /@babel/parser@7.19.3: - resolution: {integrity: sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@babel/parser@7.24.4: - resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.19.3): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.19.3): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.19.3): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.19.3): - resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.19.3): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.19.3): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.19.3): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.19.3): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/plugin-syntax-typescript@7.18.6(@babel/core@7.19.3): - resolution: {integrity: sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.19.3 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - - /@babel/template@7.18.10: - resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 - dev: true - - /@babel/template@7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.24.2 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 - dev: true - - /@babel/traverse@7.24.1: - resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.19.3: - resolution: {integrity: sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.18.10 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - - /@babel/types@7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.24.1 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: true - - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - dev: true - - /@jest/core@29.7.0(ts-node@10.9.2): - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.4.0 - exit: 0.1.2 - graceful-fs: 4.2.10 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - jest-mock: 29.7.0 - dev: true - - /@jest/expect-utils@29.1.2: - resolution: {integrity: sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.0.0 - dev: true - - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true - - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.19.32 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 18.19.32 - chalk: 4.1.2 - collect-v8-coverage: 1.0.1 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 6.0.2 - istanbul-lib-report: 3.0.0 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.0.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/schemas@29.0.0: - resolution: {integrity: sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.24.44 - dev: true - - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.27.8 - dev: true - - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - callsites: 3.1.0 - graceful-fs: 4.2.10 - dev: true - - /@jest/test-result@29.7.0: - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.1 - dev: true - - /@jest/test-sequencer@29.7.0: - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - graceful-fs: 4.2.10 - jest-haste-map: 29.7.0 - slash: 3.0.0 - dev: true - - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.19.3 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.10 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.5 - pirates: 4.0.5 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/types@29.1.2: - resolution: {integrity: sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.0.0 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.32 - '@types/yargs': 17.0.13 - chalk: 4.1.2 - dev: true - - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.32 - '@types/yargs': 17.0.13 - chalk: 4.1.2 - dev: true - - /@jridgewell/gen-mapping@0.1.1: - resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@jridgewell/gen-mapping@0.3.2: - resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.15 - dev: true - - /@jridgewell/gen-mapping@0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.25 - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - - /@jridgewell/trace-mapping@0.3.15: - resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: false - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: false - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 - dev: false - - /@sinclair/typebox@0.24.44: - resolution: {integrity: sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==} - dev: true - - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true - - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - dependencies: - '@sinonjs/commons': 3.0.1 - dev: true - - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - /@tsconfig/node16@1.0.3: - resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} - - /@types/babel__core@7.1.19: - resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} - dependencies: - '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 - '@types/babel__generator': 7.6.4 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.18.2 - dev: true - - /@types/babel__generator@7.6.4: - resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@types/babel__template@7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} - dependencies: - '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 - dev: true - - /@types/babel__traverse@7.18.2: - resolution: {integrity: sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==} - dependencies: - '@babel/types': 7.19.3 - dev: true - - /@types/fs-extra@11.0.4: - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 18.19.32 - dev: false - - /@types/graceful-fs@4.1.5: - resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} - dependencies: - '@types/node': 18.19.32 - dev: true - - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - - /@types/istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - dev: true - - /@types/istanbul-reports@3.0.1: - resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} - dependencies: - '@types/istanbul-lib-report': 3.0.0 - dev: true - - /@types/jest@29.5.12: - resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} - dependencies: - expect: 29.1.2 - pretty-format: 29.1.2 - dev: true - - /@types/jsonfile@6.1.4: - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - dependencies: - '@types/node': 18.19.32 - dev: false - - /@types/minimist@1.2.2: - resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - dev: false - - /@types/node@18.19.32: - resolution: {integrity: sha512-2bkg93YBSDKk8DLmmHnmj/Rwr18TLx7/n+I23BigFwgexUJoMHZOd8X1OFxuF/W3NN0S2W2E5sVabI5CPinNvA==} - dependencies: - undici-types: 5.26.5 - - /@types/ps-tree@1.1.2: - resolution: {integrity: sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==} - dev: false - - /@types/stack-utils@2.0.1: - resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} - dev: true - - /@types/which@3.0.3: - resolution: {integrity: sha512-2C1+XoY0huExTbs8MQv1DuS5FS86+SEjdM9F/+GS61gg5Hqbtj8ZiDSx8MfWcyei907fIPbfPGCOrNUTnVHY1g==} - dev: false - - /@types/yargs-parser@21.0.0: - resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} - dev: true - - /@types/yargs@17.0.13: - resolution: {integrity: sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - - /acorn-walk@8.2.0: - resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} - engines: {node: '>=0.4.0'} - - /acorn@8.8.0: - resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} - engines: {node: '>=0.4.0'} - hasBin: true - - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - - /anymatch@3.1.2: - resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /babel-jest@29.7.0(@babel/core@7.19.3): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.19.3 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.1.19 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.19.3) - chalk: 4.1.2 - graceful-fs: 4.2.10 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.19.0 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/template': 7.18.10 - '@babel/types': 7.19.3 - '@types/babel__core': 7.1.19 - '@types/babel__traverse': 7.18.2 - dev: true - - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.19.3): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.19.3 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.19.3) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.19.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.19.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.19.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.19.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.19.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.19.3) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.19.3): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.19.3 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.19.3) - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - - /browserslist@4.21.4: - resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001418 - electron-to-chromium: 1.4.275 - node-releases: 2.0.6 - update-browserslist-db: 1.0.10(browserslist@4.21.4) - dev: true - - /browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001607 - electron-to-chromium: 1.4.730 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.23.0) - dev: true - - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - dependencies: - fast-json-stable-stringify: 2.1.0 - dev: true - - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /caniuse-lite@1.0.30001418: - resolution: {integrity: sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==} - dev: true - - /caniuse-lite@1.0.30001607: - resolution: {integrity: sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false - - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true - - /ci-info@3.4.0: - resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==} - dev: true - - /cjs-module-lexer@1.2.2: - resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} - dev: true - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true - - /collect-v8-coverage@1.0.1: - resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true - - /convert-source-map@1.8.0: - resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 - dev: true - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /create-jest@29.7.0(@types/node@18.19.32)(ts-node@10.9.2): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.10 - jest-config: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /data-uri-to-buffer@4.0.0: - resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==} - engines: {node: '>= 12'} - dev: false - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - dev: true - - /deepmerge@4.2.2: - resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} - engines: {node: '>=0.10.0'} - dev: true - - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true - - /diff-sequences@29.0.0: - resolution: {integrity: sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: false - - /duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - dev: false - - /electron-to-chromium@1.4.275: - resolution: {integrity: sha512-aJeQQ+Hl9Jyyzv4chBqYJwmVRY46N5i2BEX5Cuyk/5gFCUZ5F3i7Hnba6snZftWla7Gglwc5pIgcd+E7cW+rPg==} - dev: true - - /electron-to-chromium@1.4.730: - resolution: {integrity: sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==} - dev: true - - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /event-stream@3.3.4: - resolution: {integrity: sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=} - dependencies: - duplexer: 0.1.2 - from: 0.1.7 - map-stream: 0.1.0 - pause-stream: 0.0.11 - split: 0.3.3 - stream-combiner: 0.0.4 - through: 2.3.8 - dev: false - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /expect@29.1.2: - resolution: {integrity: sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.1.2 - jest-get-type: 29.0.0 - jest-matcher-utils: 29.1.2 - jest-message-util: 29.1.2 - jest-util: 29.1.2 - dev: true - - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - dev: true - - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: false - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fastq@1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} - dependencies: - reusify: 1.0.4 - dev: false - - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true - - /fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 - dev: false - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - dev: true - - /formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - dependencies: - fetch-blob: 3.2.0 - dev: false - - /from@0.1.7: - resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} - dev: false - - /fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 6.1.0 - universalify: 2.0.0 - dev: false - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true - - /fx@34.0.0: - resolution: {integrity: sha512-/fZih3/WLsrtlaj2mahjWxAmyuikmcl3D5kKPqLtFmEilLsy9wp0+/vEmfvYXXhwJc+ajtCFDCf+yttXmPMHSQ==} - hasBin: true - dev: false - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: false - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - - /globby@13.2.2: - resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 4.0.0 - dev: false - - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - dev: true - - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - dev: false - - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true - - /is-core-module@2.10.0: - resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} - dependencies: - has: 1.0.3 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: false - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: false - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - dev: true - - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.19.3 - '@babel/parser': 7.19.3 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-instrument@6.0.2: - resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} - engines: {node: '>=10'} - dependencies: - '@babel/core': 7.24.4 - '@babel/parser': 7.24.4 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 7.6.0 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} - dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 - supports-color: 7.2.0 - dev: true - - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 - dev: true - - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - execa: 5.1.1 - jest-util: 29.7.0 - p-limit: 3.1.0 - dev: true - - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.5.1 - is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 - slash: 3.0.0 - stack-utils: 2.0.5 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-cli@29.7.0(@types/node@18.19.32)(ts-node@10.9.2): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.6.0 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /jest-config@29.7.0(@types/node@18.19.32)(ts-node@10.9.2): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.19.3 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - babel-jest: 29.7.0(@babel/core@7.19.3) - chalk: 4.1.2 - ci-info: 3.4.0 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - ts-node: 10.9.2(@types/node@18.19.32)(typescript@5.4.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-diff@29.1.2: - resolution: {integrity: sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.0.0 - jest-get-type: 29.0.0 - pretty-format: 29.1.2 - dev: true - - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 - dev: true - - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /jest-get-type@29.0.0: - resolution: {integrity: sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.5 - '@types/node': 18.19.32 - anymatch: 3.1.2 - fb-watchman: 2.0.2 - graceful-fs: 4.2.10 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-matcher-utils@29.1.2: - resolution: {integrity: sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.1.2 - jest-get-type: 29.0.0 - pretty-format: 29.1.2 - dev: true - - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-message-util@29.1.2: - resolution: {integrity: sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.18.6 - '@jest/types': 29.1.2 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - pretty-format: 29.1.2 - slash: 3.0.0 - stack-utils: 2.0.5 - dev: true - - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.18.6 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.5 - dev: true - - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - jest-util: 29.7.0 - dev: true - - /jest-pnp-resolver@1.2.2(jest-resolve@29.7.0): - resolution: {integrity: sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 29.7.0 - dev: true - - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.10 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.2(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.1 - resolve.exports: 2.0.2 - slash: 3.0.0 - dev: true - - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.10 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 - p-limit: 3.1.0 - source-map-support: 0.5.13 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - chalk: 4.1.2 - cjs-module-lexer: 1.2.2 - collect-v8-coverage: 1.0.1 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.19.3 - '@babel/generator': 7.19.3 - '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.19.3) - '@babel/plugin-syntax-typescript': 7.18.6(@babel/core@7.19.3) - '@babel/types': 7.19.3 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.19.3) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.10 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.6.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-util@29.1.2: - resolution: {integrity: sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.1.2 - '@types/node': 18.19.32 - chalk: 4.1.2 - ci-info: 3.4.0 - graceful-fs: 4.2.10 - picomatch: 2.3.1 - dev: true - - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - chalk: 4.1.2 - ci-info: 3.4.0 - graceful-fs: 4.2.10 - picomatch: 2.3.1 - dev: true - - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - dev: true - - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.19.32 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - dev: true - - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 18.19.32 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest@29.7.0(@types/node@18.19.32)(ts-node@10.9.2): - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) - '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - dependencies: - universalify: 2.0.0 - optionalDependencies: - graceful-fs: 4.2.10 - dev: false - - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true - - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true - - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - dev: true - - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.0 - dev: true - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - - /map-stream@0.1.0: - resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} - dev: false - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: false - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: false - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - dev: false - - /node-fetch@3.3.1: - resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - data-uri-to-buffer: 4.0.0 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - dev: false - - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true - - /node-releases@2.0.6: - resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} - dev: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - dev: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - dev: true - - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.18.6 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: false - - /pause-stream@0.0.11: - resolution: {integrity: sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=} - dependencies: - through: 2.3.8 - dev: false - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - /pirates@4.0.5: - resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} - engines: {node: '>= 6'} - dev: true - - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: true - - /pretty-format@29.1.2: - resolution: {integrity: sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.0.0 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - dev: true - - /ps-tree@1.2.0: - resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} - engines: {node: '>= 0.10'} - hasBin: true - dependencies: - event-stream: 3.3.4 - dev: false - - /pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - dev: true - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: false - - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - dev: true - - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true - dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: false - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: false - - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true - - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - dev: false - - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - - /split@0.3.3: - resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} - dependencies: - through: 2.3.8 - dev: false - - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - - /stack-utils@2.0.5: - resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - - /stream-combiner@0.0.4: - resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} - dependencies: - duplexer: 0.1.2 - dev: false - - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: false - - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - - /ts-jest@29.1.2(@babel/core@7.19.3)(jest@29.7.0)(typescript@5.4.5): - resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} - engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - '@babel/core': 7.19.3 - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.32)(ts-node@10.9.2) - jest-util: 29.1.2 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.6.0 - typescript: 5.4.5 - yargs-parser: 21.1.1 - dev: true - - /ts-node@10.9.2(@types/node@18.19.32)(typescript@5.4.5): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.3 - '@types/node': 18.19.32 - acorn: 8.8.0 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.4.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - /tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - dev: false - - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true - - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true - - /typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - - /universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} - engines: {node: '>= 10.0.0'} - dev: false - - /update-browserslist-db@1.0.10(browserslist@4.21.4): - resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.21.4 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - - /update-browserslist-db@1.0.13(browserslist@4.23.0): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.23.0 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - dev: false - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - - /v8-to-istanbul@9.0.1: - resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.8.0 - dev: true - - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - - /web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - dev: false - - /webpod@0.0.2: - resolution: {integrity: sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==} - hasBin: true - dev: false - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /which@3.0.1: - resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: false - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true - - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yaml@2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} - engines: {node: '>= 14'} - hasBin: true - dev: false - - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true - - /yargs@17.6.0: - resolution: {integrity: sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: true - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true - - /zx@7.2.3: - resolution: {integrity: sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==} - engines: {node: '>= 16.0.0'} - hasBin: true - dependencies: - '@types/fs-extra': 11.0.4 - '@types/minimist': 1.2.2 - '@types/node': 18.19.32 - '@types/ps-tree': 1.1.2 - '@types/which': 3.0.3 - chalk: 5.3.0 - fs-extra: 11.2.0 - fx: 34.0.0 - globby: 13.2.2 - minimist: 1.2.8 - node-fetch: 3.3.1 - ps-tree: 1.2.0 - webpod: 0.0.2 - which: 3.0.1 - yaml: 2.4.1 - dev: false diff --git a/.github/actions/split-tests/src/index.mts b/.github/actions/split-tests/src/index.mts deleted file mode 100644 index 43f9eb13161..00000000000 --- a/.github/actions/split-tests/src/index.mts +++ /dev/null @@ -1,74 +0,0 @@ -import { $, cd, glob, fs } from "zx"; -import path from "node:path"; -import { setOutput } from "@actions/core"; -import { SolidityConfig, SoliditySplit } from "./types.mjs"; -import { sieveSlowTests } from "./sieve.mjs"; -import { simpleSplit } from "./splitter.mjs"; - -/** - * Get a JSON formatted config file - * - * @param path The path to the config relative to the git root - */ -function getConfigFrom(path?: string): SolidityConfig { - if (!path) { - throw Error("No config path given, specify a path via $CONFIG"); - } - try { - const config = fs.readJsonSync(path); - return config; - } catch (e: unknown) { - throw Error( - `Could not find config file at path: ${path}. ${(e as Error).message}` - ); - } -} - -async function main() { - $.verbose = false; - await runAtGitRoot(); - const configPath = process.env.CONFIG; - const config = getConfigFrom(configPath); - if (config.type === "solidity") { - await handleSolidity(config); - } else { - throw Error(`Invalid config given`); - } -} -main(); - -async function handleSolidity(config: SolidityConfig) { - const { basePath, splits: configBySplit } = config; - const splits = await Promise.all( - configBySplit.map( - async ({ dir, numOfSplits, slowTests: slowTestMatchers }) => { - const globPath = path.join(basePath, dir, "/**/*.test.ts"); - const rawTests = await glob(globPath); - const pathMappedTests = rawTests.map((r) => - r.replace("contracts/", "") - ); - const { filteredTests, slowTests } = sieveSlowTests( - pathMappedTests, - slowTestMatchers - ); - const testsBySplit = simpleSplit(filteredTests, slowTests, numOfSplits); - const splits: SoliditySplit[] = testsBySplit.map((tests, i) => ({ - idx: `${dir}_${i + 1}`, - id: `${dir} ${i + 1}/${numOfSplits}`, - tests: tests.join(" "), - coverageTests: - tests.length === 1 ? tests.join(",") : `{${tests.join(",")}}`, - })); - return splits; - } - ) - ); - - const serializedSplits = JSON.stringify(splits.flat()); - setOutput("splits", serializedSplits); -} - -async function runAtGitRoot() { - const gitRoot = await $`git rev-parse --show-toplevel`; - cd(gitRoot.stdout.trimEnd()); -} diff --git a/.github/actions/split-tests/src/sieve.mts b/.github/actions/split-tests/src/sieve.mts deleted file mode 100644 index 93573669a78..00000000000 --- a/.github/actions/split-tests/src/sieve.mts +++ /dev/null @@ -1,27 +0,0 @@ -import {Tests} from "./types.mjs"; - -export function sieveSlowTests(tests: Tests, slowTestMatchers?: string[]) { - const slowTests: Tests = []; - const filteredTests: Tests = []; - - if (!slowTestMatchers) { - return {slowTests, filteredTests: tests}; - } - - // If the user supplies slow test matchers - // then we go through each test to see if we get a case sensitive match - - tests.forEach((t) => { - const isSlow = slowTestMatchers.reduce( - (isSlow, matcher) => t.includes(matcher) || isSlow, - false - ); - if (isSlow) { - slowTests.push(t); - } else { - filteredTests.push(t); - } - }); - - return {slowTests, filteredTests}; -} diff --git a/.github/actions/split-tests/src/splitter.mts b/.github/actions/split-tests/src/splitter.mts deleted file mode 100644 index f924df55087..00000000000 --- a/.github/actions/split-tests/src/splitter.mts +++ /dev/null @@ -1,43 +0,0 @@ -import {Tests, TestsBySplit} from "./types.mjs"; - -/** - * Split tests by first prioritizing slow tests being spread over each split, then filling each split by test list order. - * - * @example - * Given the following arguments: - * tests: ['foo.test', 'bar.test', 'baz.test', 'yup.test', 'nope.test'] - * slowTests: ['bonk.test', 'bop.test', 'ouch.test.ts'] - * numOfSplits: 2 - * - * We get the following output: - * 1. Spread slow tests across splits: [['bonk.test', 'ouch.test.ts'], ['bop.test']] - * 2. Insert list of tests: [['bonk.test', 'ouch.test.ts', 'foo.test', 'bar.test'], ['bop.test', 'baz.test', 'yup.test', 'nope.test']] - * - * @param tests A list of tests to distribute across splits by the test list order - * @param slowTests A list of slow tests, where the list of tests is evenly distributed across all splits before inserting regular tests - * @param numOfSplits The number of splits to spread tests across - */ -export function simpleSplit( - tests: Tests, - slowTests: Tests, - numOfSplits: number -): TestsBySplit { - const maxTestsPerSplit = Math.max(tests.length / numOfSplits); - - const testsBySplit: TestsBySplit = new Array(numOfSplits) - .fill(null) - .map(() => []); - - // Evenly distribute slow tests over each split - slowTests.forEach((test, i) => { - const splitIndex = i % numOfSplits; - testsBySplit[splitIndex].push(test); - }); - - tests.forEach((test, i) => { - const splitIndex = Math.floor(i / maxTestsPerSplit); - testsBySplit[splitIndex].push(test); - }); - - return testsBySplit; -} diff --git a/.github/actions/split-tests/src/types.mts b/.github/actions/split-tests/src/types.mts deleted file mode 100644 index 3eae2f0eb96..00000000000 --- a/.github/actions/split-tests/src/types.mts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * An array of all tests - */ -export type Tests = string[]; - -/** - * An array of tests, indexed by split - */ -export type TestsBySplit = string[][]; - -export interface Split { - /** - * The split index - * @example "4" - */ - idx: string; - - /** - * The split index in the context of all splits - * @example "4/10" - */ - id: string; -} - -export interface SoliditySplit extends Split { - /** - * A string that contains a whitespace delimited list of tests to run - * - * This format is to support the `hardhat test` command. - * @example test/foo.test.ts test/bar.test.ts - */ - tests: string; - - /** - * A string that contains a glob that expresses the list of tests to run. - * - * This format is used to conform to the --testfiles flag of solidity-coverage - * @example {test/foo.test.ts,test/bar.test.ts} - */ - coverageTests: string; -} - -/** - * Configuration file for solidity tests - */ -export interface SolidityConfig { - type: "solidity"; - /** - * The path to the contracts tests directory, relative to the git root - */ - basePath: string; - splits: { - /** - * The number of sub-splits to run across - */ - numOfSplits: number; - /** - * The directory of the tests to create sub-splits across, relative to the basePath - */ - dir: string; - /** - * An array of known slow tests, to better distribute across sub-splits - * - * Each string is a case-sensitive matcher that will match against any substring within the list of test file paths within the `dir` configuration. - * - * @example - * Given the dir `v0.8`, we get the following tests: ['v0.8/Foo1.test.ts','v0.8/bar.test.ts','v0.8/dev/eolpe/Foo.test.ts'] - * - * If we supply the following `slowTests` argument: ['Foo'] - * - * Then it'll match against both 'v0.8/Foo1.test.ts' and 'v0.8/dev/eolpe/Foo.test.ts'. - */ - slowTests?: string[]; - }[]; -} diff --git a/.github/actions/split-tests/test/__snapshots__/sieve.test.ts.snap b/.github/actions/split-tests/test/__snapshots__/sieve.test.ts.snap deleted file mode 100644 index d55bc175b8b..00000000000 --- a/.github/actions/split-tests/test/__snapshots__/sieve.test.ts.snap +++ /dev/null @@ -1,99 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`sieveSlowTests works 1`] = ` -{ - "filteredTests": [], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 2`] = ` -{ - "filteredTests": [], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 3`] = ` -{ - "filteredTests": [ - "keepme", - ], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 4`] = ` -{ - "filteredTests": [ - "keepme", - ], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 5`] = ` -{ - "filteredTests": [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - "bonk.test", - "bop.test", - "ouch.test.ts", - ], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 6`] = ` -{ - "filteredTests": [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - "bonk.test", - "bop.test", - "ouch.test.ts", - ], - "slowTests": [], -} -`; - -exports[`sieveSlowTests works 7`] = ` -{ - "filteredTests": [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - "bonk.test", - "bop.test", - ], - "slowTests": [ - "ouch.test.ts", - ], -} -`; - -exports[`sieveSlowTests works 8`] = ` -{ - "filteredTests": [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - ], - "slowTests": [ - "bonk.test", - "bop.test", - "ouch.test.ts", - ], -} -`; diff --git a/.github/actions/split-tests/test/__snapshots__/splitter.test.ts.snap b/.github/actions/split-tests/test/__snapshots__/splitter.test.ts.snap deleted file mode 100644 index 70dfe70ec15..00000000000 --- a/.github/actions/split-tests/test/__snapshots__/splitter.test.ts.snap +++ /dev/null @@ -1,119 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`simpleSplit doesn't error on empty arrays 1`] = ` -[ - [], -] -`; - -exports[`simpleSplit doesn't error on empty arrays 2`] = ` -[ - [], - [], - [], - [], - [], -] -`; - -exports[`simpleSplit handles no slow test splitting 1`] = ` -[ - [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - "bonk.test", - "bop.test", - "ouch.test.ts", - ], -] -`; - -exports[`simpleSplit handles no slow test splitting 2`] = ` -[ - [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - ], - [ - "nope.test", - "bonk.test", - "bop.test", - "ouch.test.ts", - ], -] -`; - -exports[`simpleSplit handles no slow test splitting 3`] = ` -[ - [ - "foo.test", - "bar.test", - "baz.test", - ], - [ - "yup.test", - "nope.test", - "bonk.test", - ], - [ - "bop.test", - "ouch.test.ts", - ], -] -`; - -exports[`simpleSplit handles slow test splitting 1`] = ` -[ - [ - "bonk.test", - "bop.test", - "ouch.test.ts", - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - ], -] -`; - -exports[`simpleSplit handles slow test splitting 2`] = ` -[ - [ - "bonk.test", - "ouch.test.ts", - "foo.test", - "bar.test", - "baz.test", - ], - [ - "bop.test", - "yup.test", - "nope.test", - ], -] -`; - -exports[`simpleSplit handles slow test splitting 3`] = ` -[ - [ - "bonk.test", - "foo.test", - "bar.test", - ], - [ - "bop.test", - "baz.test", - "yup.test", - ], - [ - "ouch.test.ts", - "nope.test", - ], -] -`; diff --git a/.github/actions/split-tests/test/fixtures.mts b/.github/actions/split-tests/test/fixtures.mts deleted file mode 100644 index aa87ba4c35c..00000000000 --- a/.github/actions/split-tests/test/fixtures.mts +++ /dev/null @@ -1,20 +0,0 @@ -export const testArr: string[] = [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", - "bonk.test", - "bop.test", - "ouch.test.ts", -]; - -export const testSievedArr: string[] = [ - "foo.test", - "bar.test", - "baz.test", - "yup.test", - "nope.test", -]; - -export const testSlowArr: string[] = ["bonk.test", "bop.test", "ouch.test.ts"]; diff --git a/.github/actions/split-tests/test/sieve.test.ts b/.github/actions/split-tests/test/sieve.test.ts deleted file mode 100644 index bc296a435f4..00000000000 --- a/.github/actions/split-tests/test/sieve.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {sieveSlowTests} from "../src/sieve.mjs"; -import {testArr} from "./fixtures.mjs"; - -describe("sieveSlowTests", () => { - it("works", () => { - expect(sieveSlowTests([])).toMatchSnapshot(); - expect(sieveSlowTests([], [])).toMatchSnapshot(); - expect(sieveSlowTests(["keepme"], [])).toMatchSnapshot(); - expect(sieveSlowTests(["keepme"])).toMatchSnapshot(); - expect(sieveSlowTests(testArr, [])).toMatchSnapshot(); - expect(sieveSlowTests(testArr, ["noself"])).toMatchSnapshot(); - expect(sieveSlowTests(testArr, ["ouch.test.ts"])).toMatchSnapshot(); - expect(sieveSlowTests(testArr, ["bo", "ouch.test.ts"])).toMatchSnapshot(); - }); -}); diff --git a/.github/actions/split-tests/test/splitter.test.ts b/.github/actions/split-tests/test/splitter.test.ts deleted file mode 100644 index 85ae7726fe7..00000000000 --- a/.github/actions/split-tests/test/splitter.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {simpleSplit} from "../src/splitter.mjs"; -import {testArr, testSievedArr, testSlowArr} from "./fixtures.mjs"; - -describe("simpleSplit", () => { - it("doesn't error on empty arrays", () => { - expect(simpleSplit([], [], 1)).toMatchSnapshot(); - expect(simpleSplit([], [], 5)).toMatchSnapshot(); - }); - - it("handles no slow test splitting", () => { - expect(simpleSplit(testArr, [], 1)).toMatchSnapshot(); - expect(simpleSplit(testArr, [], 2)).toMatchSnapshot(); - expect(simpleSplit(testArr, [], 3)).toMatchSnapshot(); - }); - - it("handles slow test splitting", () => { - expect(simpleSplit(testSievedArr, testSlowArr, 1)).toMatchSnapshot(); - expect(simpleSplit(testSievedArr, testSlowArr, 2)).toMatchSnapshot(); - expect(simpleSplit(testSievedArr, testSlowArr, 3)).toMatchSnapshot(); - }); -}); diff --git a/.github/actions/split-tests/tsconfig.json b/.github/actions/split-tests/tsconfig.json deleted file mode 100644 index 4b36d4a178c..00000000000 --- a/.github/actions/split-tests/tsconfig.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "NodeNext" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "NodeNext" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - "noEmit": true /* Disable emitting files from a compilation. */, - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": false /* Skip type checking all .d.ts files. */ - }, - "include": ["src", "test"] -} diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 75553412725..b3bbc115de5 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -157,7 +157,11 @@ jobs: fi IFS=',' eth_implementations="${implementations_arr[*]}" - echo "Found new releases for: $eth_implementations" + if [ -n "$eth_implementations" ]; then + echo "Found new releases for: $eth_implementations" + else + echo "No new releases found" + fi echo "evm_implementations=$eth_implementations" >> $GITHUB_OUTPUT elif [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then if [ -n "${{ github.event.inputs.base64TestList }}" ]; then @@ -229,7 +233,7 @@ jobs: check-ecr-images-exist: name: Check images used as test dependencies exist in ECR - if: always() && needs.should-run.outputs.should_run == 'true' + if: always() && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration permissions: id-token: write @@ -263,7 +267,7 @@ jobs: page_size: ${{matrix.mirror.page_size}} build-chainlink: - if: always() && needs.should-run.outputs.should_run == 'true' + if: always() && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration permissions: id-token: write @@ -298,7 +302,7 @@ jobs: get-latest-available-images: name: Get Latest EVM Implementation's Images - if: always() && needs.should-run.outputs.should_run == 'true' + if: always() && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration runs-on: ubuntu-latest needs: [check-ecr-images-exist, should-run, select-versions] @@ -371,7 +375,7 @@ jobs: prepare-compatibility-matrix: name: Prepare Compatibility Matrix - if: always() && needs.should-run.outputs.should_run == 'true' + if: always() && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration permissions: checks: write @@ -501,7 +505,7 @@ jobs: run-client-compatibility-matrix: name: ${{ matrix.evm_node.product }} compatibility with ${{ matrix.evm_node.docker_image }} - if: always() && needs.should-run.outputs.should_run == 'true' && needs.build-chainlink.result == 'success' + if: always() && needs.should-run.outputs.should_run == 'true' && needs.build-chainlink.result == 'success' && needs.prepare-compatibility-matrix.outputs.matrix != '' environment: integration permissions: checks: write @@ -605,7 +609,7 @@ jobs: start-slack-thread: name: Start Slack Thread - if: always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' + if: always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration outputs: thread_ts: ${{ steps.slack.outputs.thread_ts }} @@ -664,7 +668,7 @@ jobs: parse-test-results: name: Parse Test Results - if: always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' + if: always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '') environment: integration permissions: checks: write @@ -750,7 +754,7 @@ jobs: post-test-results-to-slack: name: Post Test Results for ${{matrix.product}} - if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' }} + if: always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' && needs.should-run.outputs.should_run == 'true' && needs.parse-test-results.result == 'success' environment: integration permissions: checks: write diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index a291b0581a1..82eca4294a0 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -323,6 +323,7 @@ jobs: fi - name: Setup GAP for Grafana uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2 + id: setup-gap with: # aws inputs aws-region: ${{ secrets.AWS_REGION }} @@ -386,7 +387,7 @@ jobs: - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@a8afe9cb511125685ce02bb8694298ca89685028 # v2.3.23 eth-smoke-tests-matrix-log-poller: if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') || inputs.distinct_run_name != '' }} @@ -438,6 +439,7 @@ jobs: fi - name: Setup GAP for Grafana uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2 + id: setup-gap with: # aws inputs aws-region: ${{ secrets.AWS_REGION }} @@ -498,6 +500,11 @@ jobs: path: .covdata retention-days: 1 + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@a8afe9cb511125685ce02bb8694298ca89685028 # v2.3.23 + + eth-smoke-tests-matrix: if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration @@ -656,17 +663,21 @@ jobs: -v $PWD/../../integration-tests/smoke/traces:/tracing \ --user "$(id -u):$(id -g)" \ -p 4317:4317 otel/opentelemetry-collector:0.88.0 --config=/etc/otel-collector.yaml + - name: Locate Docker Volume id: locate-volume if: false run: | echo "VOLUME_PATH=$(docker volume inspect --format '{{ .Mountpoint }}' otel-traces)" >> $GITHUB_OUTPUT + - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | docker logs otel-collector + - name: Setup GAP for Grafana uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2 + id: setup-gap with: # aws inputs aws-region: ${{ secrets.AWS_REGION }} @@ -674,6 +685,7 @@ jobs: api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} # other inputs duplicate-authorization-header: "true" + - name: Prepare Base64 TOML override uses: ./.github/actions/setup-create-base64-config with: @@ -692,6 +704,7 @@ jobs: grafanaUrl: "http://localhost:8080/primary" grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" grafanaBearerToken: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }} + ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' @@ -740,23 +753,27 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" should_tidy: "false" + - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | docker logs otel-collector + - name: Permissions on traces if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | ls -l ./integration-tests/smoke/traces + - name: Upload Trace Data if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json + - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@a8afe9cb511125685ce02bb8694298ca89685028 # v2.3.23 with: test_directory: ./integration-tests/smoke/ @@ -842,7 +859,6 @@ jobs: # Run the setup if the matrix finishes but this time save the cache if we have a cache hit miss # this will also only run if both of the matrix jobs pass eth-smoke-go-mod-cache: - environment: integration needs: [eth-smoke-tests] runs-on: ubuntu-latest diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index ae24786b437..c4415ac85d5 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -8,7 +8,10 @@ on: default: TestOCRSoak type: choice options: - - TestOCRSoak + - TestOCRv1Soak + - TestOCRv2Soak + - TestForwarderOCRv1Soak + - TestForwarderOCRv2Soak - TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled - TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled - TestOCRSoak_GasSpike @@ -18,7 +21,7 @@ on: base64Config: description: base64-ed config required: true - type: string + type: string slackMemberID: description: Slack Member ID (Not your @) required: true @@ -78,7 +81,7 @@ jobs: echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY - echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Image uses: ./.github/actions/build-test-image with: diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index bfbca1c6324..a7ced0f5653 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -16,16 +16,12 @@ jobs: - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: - # Foundry is only used for Solidity v0.8 contracts, therefore we can ignore - # changes to older contracts. filters: | src: - 'contracts/src/v0.8/**/*' - '.github/workflows/solidity-foundry.yml' - 'contracts/foundry.toml' - 'contracts/gas-snapshots/*.gas-snapshot' - - 'contracts/foundry-lib/**/*' - - '.gitmodules' tests: strategy: diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 9b5058eda6a..fb6ba6fef43 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -25,46 +25,17 @@ jobs: with: filters: | src: - - 'contracts/src/!(v0.8/(llo-feeds|keystone|ccip|functions|transmission)/**)/**/*' + - 'contracts/src/!(v0.8/(ccip|functions|keystone|l2ep|llo-feeds|transmission|vrf)/**)/**/*' - 'contracts/test/**/*' - 'contracts/package.json' - 'contracts/pnpm-lock.yaml' - 'contracts/hardhat.config.ts' - - 'contracts/ci.json' - '.github/workflows/solidity-hardhat.yml' - split-tests: - name: Split Solidity Tests - runs-on: ubuntu-latest - outputs: - splits: ${{ steps.split.outputs.splits }} - steps: - - name: Checkout the repo - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Generate splits - id: split - uses: ./.github/actions/split-tests - with: - config: ./contracts/ci.json - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1 - with: - id: solidity-split-tests - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Split Solidity Tests - continue-on-error: true - - solidity-splits: - needs: [changes, split-tests] + hardhat-test: + needs: [changes] if: needs.changes.outputs.changes == 'true' - name: Solidity ${{ matrix.split.id }} ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} - strategy: - fail-fast: false - matrix: - split: ${{ fromJson(needs.split-tests.outputs.splits) }} + name: Solidity ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} runs-on: ubuntu-latest steps: - name: Checkout the repo @@ -76,23 +47,20 @@ jobs: with: namespace: coverage - name: Run tests - env: - SPLIT: ${{ matrix.split.tests }} working-directory: contracts - run: pnpm test -- $SPLIT + run: pnpm test - name: Collect Metrics id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1 with: - id: solidity-splits + id: hardhat-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Solidity ${{ matrix.split.id }} continue-on-error: true solidity: - needs: [changes, solidity-splits] + needs: [changes, hardhat-test] name: Solidity runs-on: ubuntu-latest if: always() diff --git a/.tool-versions b/.tool-versions index ca10fd5f6a8..f660f2ac116 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,5 +1,5 @@ golang 1.21.7 -mockery 2.42.2 +mockery 2.43.2 nodejs 20.13.1 pnpm 9.4.0 postgres 15.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7662247a36f..f2124455030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,99 +1,136 @@ # Changelog Chainlink Core -## 2.13.0 - UNRELEASED +## 2.14.0 - UNRELEASED ### Minor Changes -- [#13235](https://github.com/smartcontractkit/chainlink/pull/13235) [`5374a577dd`](https://github.com/smartcontractkit/chainlink/commit/5374a577dd6396e149c26168a2f093b3204dfddb) Thanks [@krehermann](https://github.com/krehermann)! - #internal move workflow validation to common repo +- [#13356](https://github.com/smartcontractkit/chainlink/pull/13356) [`0228243f20`](https://github.com/smartcontractkit/chainlink/commit/0228243f20bb02d40c7ad2c9cf1002599436ff1d) Thanks [@ilija42](https://github.com/ilija42)! - #internal Add Log Poller support to Chain Reader through setting them in config. All filters should be part of the contract wide filter unless an event needs specific polling configuration, which can be set on a per event basis.. -- [#12970](https://github.com/smartcontractkit/chainlink/pull/12970) [`1eb7180205`](https://github.com/smartcontractkit/chainlink/commit/1eb71802053fcde7e809ef58918110cf03046f3a) Thanks [@dimriou](https://github.com/dimriou)! - Decouple client tests from core #internal +- [#13718](https://github.com/smartcontractkit/chainlink/pull/13718) [`f33cd1915c`](https://github.com/smartcontractkit/chainlink/commit/f33cd1915c03bef9bfe110481eb13094c36ce454) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal Added a chain writer constructor onto the evm relayer. -- [#13354](https://github.com/smartcontractkit/chainlink/pull/13354) [`58d73ecf61`](https://github.com/smartcontractkit/chainlink/commit/58d73ecf618ac39c37f767e70c4e6d6a51eaba59) Thanks [@friedemannf](https://github.com/friedemannf)! - #breaking_change Remove the `xdai` `ChainType` config option. Moving forward, only `gnosis` can be used. +- [#13040](https://github.com/smartcontractkit/chainlink/pull/13040) [`0ac790b37f`](https://github.com/smartcontractkit/chainlink/commit/0ac790b37fca951dfb4b4093c00c5adbd6987668) Thanks [@amit-momin](https://github.com/amit-momin)! - Added API for products to query a transaction's status in the TXM #internal -- [#12971](https://github.com/smartcontractkit/chainlink/pull/12971) [`a2441ba8cc`](https://github.com/smartcontractkit/chainlink/commit/a2441ba8cc44b6455338410b739d394a3bf3557e) Thanks [@dimriou](https://github.com/dimriou)! - Decouple evm config tests from core #internal +- [#13413](https://github.com/smartcontractkit/chainlink/pull/13413) [`9e733a07fe`](https://github.com/smartcontractkit/chainlink/commit/9e733a07fe2082207e6d7884abee26d82d37e808) Thanks [@silaslenihan](https://github.com/silaslenihan)! - #added EVM implementation of GetFeeComponents function for ChainWriter -- [#13396](https://github.com/smartcontractkit/chainlink/pull/13396) [`5ff32bde25`](https://github.com/smartcontractkit/chainlink/commit/5ff32bde2575d2b2ef626a69d54b9f6eed0d21c5) Thanks [@ettec](https://github.com/ettec)! - #internal keystone: handle local target transmission logic in capability wrapper +- [#13478](https://github.com/smartcontractkit/chainlink/pull/13478) [`9f6e454bc5`](https://github.com/smartcontractkit/chainlink/commit/9f6e454bc51c07cf817c90a9a11fa44ae3708be5) Thanks [@snehaagni](https://github.com/snehaagni)! - Bump to start the next version -- [#13357](https://github.com/smartcontractkit/chainlink/pull/13357) [`21f38e52d1`](https://github.com/smartcontractkit/chainlink/commit/21f38e52d1d2401f58da83f143043e3f4561e21c) Thanks [@ettec](https://github.com/ettec)! - #internal remote target capability and transmission protocol +- [#13501](https://github.com/smartcontractkit/chainlink/pull/13501) [`15f02f65c1`](https://github.com/smartcontractkit/chainlink/commit/15f02f65c1ac3cfc89e726597a981ddf206eea2b) Thanks [@ettec](https://github.com/ettec)! - #internal remove shared secret from transmission schedule -- [#13397](https://github.com/smartcontractkit/chainlink/pull/13397) [`daf8cf6cfe`](https://github.com/smartcontractkit/chainlink/commit/daf8cf6cfe1c0b8d2a70fb476a4e815af5025ebe) Thanks [@dimriou](https://github.com/dimriou)! - Remove multiple core dependencies from evm head tracker tests #internal" +- [#13691](https://github.com/smartcontractkit/chainlink/pull/13691) [`f2630b280d`](https://github.com/smartcontractkit/chainlink/commit/f2630b280d917313c6d3af468d9a7c039d5e179e) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal Implemented the `GetTransactionStatus` method on the EVM implementation of the `ChainWriter`. -- [#13312](https://github.com/smartcontractkit/chainlink/pull/13312) [`c3829cac20`](https://github.com/smartcontractkit/chainlink/commit/c3829cac20e158f805d0efb9a8a2183e8d7b0515) Thanks [@amit-momin](https://github.com/amit-momin)! - #internal Added new Geth InsufficientEth client error for internal TXM classification +- [#13551](https://github.com/smartcontractkit/chainlink/pull/13551) [`f7e036244c`](https://github.com/smartcontractkit/chainlink/commit/f7e036244c1bf019964704734a96be5e5699ca2c) Thanks [@ettec](https://github.com/ettec)! - #internal capability dispatcher threading and context usage -- [#13381](https://github.com/smartcontractkit/chainlink/pull/13381) [`0a62f024e1`](https://github.com/smartcontractkit/chainlink/commit/0a62f024e10398cdd6451ef0d15db2501de11538) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal Pre-process contract abis in the evm chainwriter. +- [#13564](https://github.com/smartcontractkit/chainlink/pull/13564) [`2c2ca6a278`](https://github.com/smartcontractkit/chainlink/commit/2c2ca6a27899295dc87e48e4378671dbbe06ac48) Thanks [@yongkangchia](https://github.com/yongkangchia)! - #changed Added Aptos Keystore to Core. This includes Aptos Key which uses ED25519, Keystore, Relevant tests -- [#13221](https://github.com/smartcontractkit/chainlink/pull/13221) [`0b100ad3db`](https://github.com/smartcontractkit/chainlink/commit/0b100ad3dbf0a3c2fbd6e55c539046f6f3c9e5f6) Thanks [@ilija42](https://github.com/ilija42)! - Added a mechanism to validate forwarders for OCR2 and fallback to EOA if necessary #added +- [#13427](https://github.com/smartcontractkit/chainlink/pull/13427) [`66f154745d`](https://github.com/smartcontractkit/chainlink/commit/66f154745d3d973aa8b629a99a65a660a1d1b3bc) Thanks [@cedric-cordenier](https://github.com/cedric-cordenier)! - #internal Add RegistrySyncer -- [#13416](https://github.com/smartcontractkit/chainlink/pull/13416) [`68e00b3abf`](https://github.com/smartcontractkit/chainlink/commit/68e00b3abf566a222ff6775b0fb2575ff73f735e) Thanks [@ettec](https://github.com/ettec)! - #internal fix for workflow step persistence +- [#13661](https://github.com/smartcontractkit/chainlink/pull/13661) [`363e8290bb`](https://github.com/smartcontractkit/chainlink/commit/363e8290bb5ea2f7bf07528ba19cc64dca8e87a8) Thanks [@amit-momin](https://github.com/amit-momin)! - Updated L1 gas price calculations for Optimism Ecotone and Fjord upgrades #internal -- [#13259](https://github.com/smartcontractkit/chainlink/pull/13259) [`76dbe19282`](https://github.com/smartcontractkit/chainlink/commit/76dbe192822c7e9f289c98e33ebb6693a07046a0) Thanks [@archseer](https://github.com/archseer)! - #internal Added a configuration option to chain writer to set the tx send strategy. +- [#13297](https://github.com/smartcontractkit/chainlink/pull/13297) [`e55e0424a2`](https://github.com/smartcontractkit/chainlink/commit/e55e0424a276416cf849a83a1488a287872824c5) Thanks [@amit-momin](https://github.com/amit-momin)! - #changed Refactored the BlockHistoryEstimator check to prevent excessively bumping transactions. Check no longer waits for CheckInclusionBlocks to pass before assessing an attempt. + #bugfix Fixed a bug that would use the oldest blocks in the cached history instead of the latest to perform gas estimations. -- [#13384](https://github.com/smartcontractkit/chainlink/pull/13384) [`bc087f1de2`](https://github.com/smartcontractkit/chainlink/commit/bc087f1de2014cce1027341d14e0917c4351fb21) Thanks [@augustbleeds](https://github.com/augustbleeds)! - bump chainlink-starknet so it builds reports with median gas price #updated +- [#13524](https://github.com/smartcontractkit/chainlink/pull/13524) [`d736d9e083`](https://github.com/smartcontractkit/chainlink/commit/d736d9e0838983a021677bc608556b3994f46690) Thanks [@ettec](https://github.com/ettec)! - #internal remote target wait until initiated threads exit on close -- [#13353](https://github.com/smartcontractkit/chainlink/pull/13353) [`7a86103474`](https://github.com/smartcontractkit/chainlink/commit/7a861034740a44ebb5d3f1da2d271637691c0bd3) Thanks [@pavel-raykov](https://github.com/pavel-raykov)! - #updated Remove deprecated app.shortcut links +- [#13169](https://github.com/smartcontractkit/chainlink/pull/13169) [`3f56b3eecd`](https://github.com/smartcontractkit/chainlink/commit/3f56b3eecd2d5fd3e325325d9d1e82d8a749d9eb) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal rework operator_ui installer -- [#13181](https://github.com/smartcontractkit/chainlink/pull/13181) [`c14576a945`](https://github.com/smartcontractkit/chainlink/commit/c14576a945fdc6b5099ffd31f467a0712afe6fd6) Thanks [@krehermann](https://github.com/krehermann)! - #added workflow spec auto-approval via CLO +- [#13601](https://github.com/smartcontractkit/chainlink/pull/13601) [`c3f6b704f1`](https://github.com/smartcontractkit/chainlink/commit/c3f6b704f1c510dbfb28b421ee3a8f63416b18c1) Thanks [@cedric-cordenier](https://github.com/cedric-cordenier)! - #internal Allow outputs to be passed directly to the inputs -- [#13455](https://github.com/smartcontractkit/chainlink/pull/13455) [`066afc0877`](https://github.com/smartcontractkit/chainlink/commit/066afc0877a9e953bbda25a4ff09009d7f1c1e2d) Thanks [@krehermann](https://github.com/krehermann)! - #bugfix use correct internal id in workflow auto-approval +- [#13621](https://github.com/smartcontractkit/chainlink/pull/13621) [`3eb0a3736f`](https://github.com/smartcontractkit/chainlink/commit/3eb0a3736ff1cc885dd7ff9c978c09218f61e7a6) Thanks [@cedric-cordenier](https://github.com/cedric-cordenier)! - #internal Add script to provision capability registry -- [#13259](https://github.com/smartcontractkit/chainlink/pull/13259) [`76dbe19282`](https://github.com/smartcontractkit/chainlink/commit/76dbe192822c7e9f289c98e33ebb6693a07046a0) Thanks [@archseer](https://github.com/archseer)! - #internal added tests for Chainwriter +- [#13522](https://github.com/smartcontractkit/chainlink/pull/13522) [`90924dcc26`](https://github.com/smartcontractkit/chainlink/commit/90924dcc2667807f57e31992aac9f674935680b8) Thanks [@krehermann](https://github.com/krehermann)! - #internal moves workflow name and owner to the yaml spec -- [#12881](https://github.com/smartcontractkit/chainlink/pull/12881) [`d675d864f0`](https://github.com/smartcontractkit/chainlink/commit/d675d864f0e6f33c783bfed17fe31b2c127eb51d) Thanks [@amit-momin](https://github.com/amit-momin)! - #added Added an auto-purge feature to the EVM TXM that identifies terminally stuck transactions either through a chain specific method or heurisitic then purges them to unblock the nonce. Included 4 new toml configs under Transactions.AutoPurge to configure this new feature: Enabled, Threshold, MinAttempts, and DetectionApiUrl. +- [#13668](https://github.com/smartcontractkit/chainlink/pull/13668) [`e5dc01e844`](https://github.com/smartcontractkit/chainlink/commit/e5dc01e844064e2fdab976369cf83195f9659216) Thanks [@cedric-cordenier](https://github.com/cedric-cordenier)! - Add registry syncer package #internal -- [#13401](https://github.com/smartcontractkit/chainlink/pull/13401) [`905830c3ff`](https://github.com/smartcontractkit/chainlink/commit/905830c3ff16c670c3fbf3d83a0c2ca3a15e83a8) Thanks [@krehermann](https://github.com/krehermann)! - #db_update add persistence for DON-2-DON discovery announcements +### Patch Changes -- [#13466](https://github.com/smartcontractkit/chainlink/pull/13466) [`4fdfffdb4c`](https://github.com/smartcontractkit/chainlink/commit/4fdfffdb4c4a6f16fcdb388fe38642398ce130da) Thanks [@dimriou](https://github.com/dimriou)! - Move chaintype #internal +- [#13498](https://github.com/smartcontractkit/chainlink/pull/13498) [`c6f1b30f34`](https://github.com/smartcontractkit/chainlink/commit/c6f1b30f346c0a8a64ed39b8317e247c928a368e) Thanks [@simsonraj](https://github.com/simsonraj)! - #added zkSync L1 GasPrice calculation -- [#13200](https://github.com/smartcontractkit/chainlink/pull/13200) [`4718aa7ec2`](https://github.com/smartcontractkit/chainlink/commit/4718aa7ec20e2ef70dff7fb72095d357f3725a80) Thanks [@augustbleeds](https://github.com/augustbleeds)! - Add option to include GasPriceSubunits pipeline to include gasPriceSubunits in median ocr2 transmission (only to be used with Starknet chain for now) #added #nops #updated +- [#13487](https://github.com/smartcontractkit/chainlink/pull/13487) [`5e27da95f0`](https://github.com/smartcontractkit/chainlink/commit/5e27da95f09f21272e93f086bc2de5a9bc2ae399) Thanks [@bolekk](https://github.com/bolekk)! - #internal Use audited version of OCR2Base.sol in OCR3Capability.sol + +- [#13612](https://github.com/smartcontractkit/chainlink/pull/13612) [`98108568dc`](https://github.com/smartcontractkit/chainlink/commit/98108568dc3ea54537a6867d36f3e48ee456daae) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal bump `chainlink-common` version to commit 6d926be950a6f6ca289a84edad938d4eef2ee337. -- [#13215](https://github.com/smartcontractkit/chainlink/pull/13215) [`66d8d16638`](https://github.com/smartcontractkit/chainlink/commit/66d8d16638f16dc863cbc6d24356c3cf3c9724f0) Thanks [@ettec](https://github.com/ettec)! - #internal standard capability support +- [#13726](https://github.com/smartcontractkit/chainlink/pull/13726) [`2ecf45d381`](https://github.com/smartcontractkit/chainlink/commit/2ecf45d381b98714f4f673221bfc74577fcfeb04) Thanks [@ferglor](https://github.com/ferglor)! - Only encode non nil block numbers for eth_call #changed -- [#12995](https://github.com/smartcontractkit/chainlink/pull/12995) [`322f3b9616`](https://github.com/smartcontractkit/chainlink/commit/322f3b96162a4e0738d76ba00f949c5b19d09909) Thanks [@dimriou](https://github.com/dimriou)! - Decouple monitoring tests from core #internal +- [#13048](https://github.com/smartcontractkit/chainlink/pull/13048) [`3f8c00a6f1`](https://github.com/smartcontractkit/chainlink/commit/3f8c00a6f1884f765bbe9e4b70e0dc4fb94a0088) Thanks [@dhaidashenko](https://github.com/dhaidashenko)! - Fixed local finality violation caused by an RPC lagging behind on latest finalized block. -- [#12972](https://github.com/smartcontractkit/chainlink/pull/12972) [`1196df4684`](https://github.com/smartcontractkit/chainlink/commit/1196df4684c812361b8f0994ade6414a1f214c2c) Thanks [@dimriou](https://github.com/dimriou)! - Decouple gas tests from core #internal + Added `EVM.FinalizedBlockOffset` and `EVM.NodePool.EnforceRepeatableRead` config options. + With `EnforceRepeatableRead = true`, RPC is considered healthy only if its most recent finalized block is larger or equal to the highest finalized block observed by the Node minus `FinalizedBlockOffset`. + #bugfix -- [#12993](https://github.com/smartcontractkit/chainlink/pull/12993) [`2a8d1b150a`](https://github.com/smartcontractkit/chainlink/commit/2a8d1b150a07c5dfd036559a35c8f83bb3e4f757) Thanks [@dimriou](https://github.com/dimriou)! - Decouple utils tests from core #internal +- [#13554](https://github.com/smartcontractkit/chainlink/pull/13554) [`22cab6c152`](https://github.com/smartcontractkit/chainlink/commit/22cab6c1526371c898bde52e7836cfd01ba7daf5) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal Bumped `chainlink-common` package version to commit `1fb0b48758af25d689b6957ebfb76598c9fb27ea`. -- [#13445](https://github.com/smartcontractkit/chainlink/pull/13445) [`3ff5128026`](https://github.com/smartcontractkit/chainlink/commit/3ff51280266dd979cbe2a8fe779c669a4e12fe22) Thanks [@ettec](https://github.com/ettec)! - #internal update operator ui versioun +- [#13670](https://github.com/smartcontractkit/chainlink/pull/13670) [`253a962fa3`](https://github.com/smartcontractkit/chainlink/commit/253a962fa3997765d5df40cf5ca19f5471ed5976) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal bumped chainlink-common version to commit 1eff5dedc9857ed8811186dd2996603942dc1107 -- [#13259](https://github.com/smartcontractkit/chainlink/pull/13259) [`76dbe19282`](https://github.com/smartcontractkit/chainlink/commit/76dbe192822c7e9f289c98e33ebb6693a07046a0) Thanks [@archseer](https://github.com/archseer)! - #added A ChainWriter implementation in the EVM relay. +- [#13459](https://github.com/smartcontractkit/chainlink/pull/13459) [`8fdc77f6a7`](https://github.com/smartcontractkit/chainlink/commit/8fdc77f6a7c30be5254bd9d0cb75fd6b2736242e) Thanks [@makramkd](https://github.com/makramkd)! - #db_update ccip capability specs migration -- [#13265](https://github.com/smartcontractkit/chainlink/pull/13265) [`5db47b63b3`](https://github.com/smartcontractkit/chainlink/commit/5db47b63b3f2d0addf521904940d780caf9f57eb) Thanks [@krehermann](https://github.com/krehermann)! - #db_update Add name to workflow spec. Add unique constraint to (owner,name) for workflow spec +- [#13494](https://github.com/smartcontractkit/chainlink/pull/13494) [`a830fe093f`](https://github.com/smartcontractkit/chainlink/commit/a830fe093f4642236a89ac73bf9eefe5008898bc) Thanks [@HelloKashif](https://github.com/HelloKashif)! - #internal removed HistoryDepth to FinalityDepth validation -- [#13089](https://github.com/smartcontractkit/chainlink/pull/13089) [`b00ad69095`](https://github.com/smartcontractkit/chainlink/commit/b00ad6909571042947f615b8740c31c304bbf7ec) Thanks [@silaslenihan](https://github.com/silaslenihan)! - #internal Switched finality check in HeadTracker to use the underlying finality type +- [#13580](https://github.com/smartcontractkit/chainlink/pull/13580) [`0d4a3b2cd8`](https://github.com/smartcontractkit/chainlink/commit/0d4a3b2cd8ff938ba018d982ef514c754a7df345) Thanks [@DeividasK](https://github.com/DeividasK)! - #internal -### Patch Changes +- [#13569](https://github.com/smartcontractkit/chainlink/pull/13569) [`f5a70eb09a`](https://github.com/smartcontractkit/chainlink/commit/f5a70eb09abc9a4d859442c9bd062a74a7ec9c54) Thanks [@DeividasK](https://github.com/DeividasK)! - #internal -- [#13377](https://github.com/smartcontractkit/chainlink/pull/13377) [`390ee1990e`](https://github.com/smartcontractkit/chainlink/commit/390ee1990e2545d4f47e64a521ee61ee0b200786) Thanks [@bolekk](https://github.com/bolekk)! - #internal handle new metadata fields +- [#13528](https://github.com/smartcontractkit/chainlink/pull/13528) [`95502ad269`](https://github.com/smartcontractkit/chainlink/commit/95502ad2699d63891662594f70e82e76682f2ed8) Thanks [@DeividasK](https://github.com/DeividasK)! - #internal -- [#13315](https://github.com/smartcontractkit/chainlink/pull/13315) [`3af83ed014`](https://github.com/smartcontractkit/chainlink/commit/3af83ed01439648354ac6b348d61b0f9594b99ec) Thanks [@mateusz-sekara](https://github.com/mateusz-sekara)! - Reducing the scope of 0233 migration to include only 5th word index which is required for CCIP #db_update +- [#13563](https://github.com/smartcontractkit/chainlink/pull/13563) [`99fa0e68d1`](https://github.com/smartcontractkit/chainlink/commit/99fa0e68d11f4bbc5bc54c6c65edb1db024b21a9) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal Clean up workflow engine logging -- [#13139](https://github.com/smartcontractkit/chainlink/pull/13139) [`15fab1daa8`](https://github.com/smartcontractkit/chainlink/commit/15fab1daa84348e96a7895280209cb73e456a1c5) Thanks [@jmank88](https://github.com/jmank88)! - core/services: fix ocrWrapper saveError contexts #internal +- [#13443](https://github.com/smartcontractkit/chainlink/pull/13443) [`955566fb9b`](https://github.com/smartcontractkit/chainlink/commit/955566fb9b9a4f930069d497a81bb6c37fac0125) Thanks [@Tofel](https://github.com/Tofel)! - #changed Expand EVM implementation compatibility pipeline -- [#13144](https://github.com/smartcontractkit/chainlink/pull/13144) [`49f1bf3ba2`](https://github.com/smartcontractkit/chainlink/commit/49f1bf3ba296f0e3dfc01d5a3d371f82f159dc4a) Thanks [@jmank88](https://github.com/jmank88)! - improve handling of postgres connection settings and driver versions #db +- [#13602](https://github.com/smartcontractkit/chainlink/pull/13602) [`fc3a291d6c`](https://github.com/smartcontractkit/chainlink/commit/fc3a291d6c75e8045c3f8e2458ec7513ffdb3882) Thanks [@nickcorin](https://github.com/nickcorin)! - #internal fixed a bug where we weren't sending the value param to the txm -- [#13286](https://github.com/smartcontractkit/chainlink/pull/13286) [`6139126034`](https://github.com/smartcontractkit/chainlink/commit/61391260340ba74f3510e6ded4fdace6829630b7) Thanks [@EasterTheBunny](https://github.com/EasterTheBunny)! - enforce proper result indexing on pipeline results #breaking_change +- [#13714](https://github.com/smartcontractkit/chainlink/pull/13714) [`4b19e37553`](https://github.com/smartcontractkit/chainlink/commit/4b19e37553ecf60c9d98209bc29b4079ae64cbe3) Thanks [@shileiwill](https://github.com/shileiwill)! - add native billing in smoke test #added -- [#13279](https://github.com/smartcontractkit/chainlink/pull/13279) [`5a87f4a59e`](https://github.com/smartcontractkit/chainlink/commit/5a87f4a59e3c6c92b08ebefc5090017693785729) Thanks [@DylanTinianov](https://github.com/DylanTinianov)! - #changed Remove ClientErrors interface from common +- [#13426](https://github.com/smartcontractkit/chainlink/pull/13426) [`592b2bb5a8`](https://github.com/smartcontractkit/chainlink/commit/592b2bb5a84a0e8858f77c5faa99e881f911878c) Thanks [@archseer](https://github.com/archseer)! - #internal + +- [#13546](https://github.com/smartcontractkit/chainlink/pull/13546) [`10ddafaebe`](https://github.com/smartcontractkit/chainlink/commit/10ddafaebedb94ad5a59968d19256b8c4592857f) Thanks [@cds95](https://github.com/cds95)! - #internal upgrade keystone contracts to 0.8.24 + +- [#13504](https://github.com/smartcontractkit/chainlink/pull/13504) [`815c5ea871`](https://github.com/smartcontractkit/chainlink/commit/815c5ea8715462e00f6ea10cdc0b93ec3e1ba505) Thanks [@shileiwill](https://github.com/shileiwill)! - move v23 contracts #bugfix + +- [#13583](https://github.com/smartcontractkit/chainlink/pull/13583) [`8ccaa140ae`](https://github.com/smartcontractkit/chainlink/commit/8ccaa140aebdafbb760569a1d2b7cabe8ac1bf61) Thanks [@samsondav](https://github.com/samsondav)! - Add new relayer type "dummy" for testing. -- [#13190](https://github.com/smartcontractkit/chainlink/pull/13190) [`c93e83ab99`](https://github.com/smartcontractkit/chainlink/commit/c93e83ab992c5238ec79f9581f2eb370d9862492) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal Add Keystone CRIB Provisioning + #added -- [#13008](https://github.com/smartcontractkit/chainlink/pull/13008) [`841fe61daa`](https://github.com/smartcontractkit/chainlink/commit/841fe61daa90b980f1e1622d2f7bd8f850b55462) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal Keystone - rename type -> id +- [#13671](https://github.com/smartcontractkit/chainlink/pull/13671) [`4493b96f62`](https://github.com/smartcontractkit/chainlink/commit/4493b96f62d18376d89ae152cb0df3eab87ab5fd) Thanks [@poopoothegorilla](https://github.com/poopoothegorilla)! - #bugfix fixed ureachable code bug which could result in stuck txns -- [#13436](https://github.com/smartcontractkit/chainlink/pull/13436) [`f37afb9eba`](https://github.com/smartcontractkit/chainlink/commit/f37afb9ebaeda10f8b3873b069b8a824e60a81c3) Thanks [@bolekk](https://github.com/bolekk)! - #internal #bugfix keystone bugfixes +- [#13376](https://github.com/smartcontractkit/chainlink/pull/13376) [`bb40d51502`](https://github.com/smartcontractkit/chainlink/commit/bb40d51502487b010a1d6621db42458356dbbdc0) Thanks [@shileiwill](https://github.com/shileiwill)! - add events, add getter and add comments #bugfix -- [#13214](https://github.com/smartcontractkit/chainlink/pull/13214) [`921a015792`](https://github.com/smartcontractkit/chainlink/commit/921a015792570ad3fa3b7700bdd3ec8f0590b383) Thanks [@momentmaker](https://github.com/momentmaker)! - Add to CI changeset workflow an additional step to update the Jira issue associated with this PR and set the `fixVersions` for the issue with the upcoming core release version. #internal #wip +- [#13495](https://github.com/smartcontractkit/chainlink/pull/13495) [`483ee6ae06`](https://github.com/smartcontractkit/chainlink/commit/483ee6ae06f608d150ab360e0a3ffe6895b39d52) Thanks [@pavel-raykov](https://github.com/pavel-raykov)! - #updated Fix verb formatting in the log outputs. -- [#13449](https://github.com/smartcontractkit/chainlink/pull/13449) [`69a95d8262`](https://github.com/smartcontractkit/chainlink/commit/69a95d82626290858219250e746fd51c8c7c4093) Thanks [@dimriou](https://github.com/dimriou)! - Cleanup txm tests #internal +- [#13599](https://github.com/smartcontractkit/chainlink/pull/13599) [`e0ce0795b4`](https://github.com/smartcontractkit/chainlink/commit/e0ce0795b44f27539611327efce7c7c004511daa) Thanks [@pavel-raykov](https://github.com/pavel-raykov)! - #internal Add loggercheck linter to verify that \*w logging methods have even number of args. -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal add modify DON function to capability registry +## 2.13.0 - 2024-07-01 -- [#13453](https://github.com/smartcontractkit/chainlink/pull/13453) [`8c98c80376`](https://github.com/smartcontractkit/chainlink/commit/8c98c80376c3b6d72bffeab62ee45a74449b6ef5) Thanks [@cds95](https://github.com/cds95)! - #internal return hashed capability ids +### Minor Changes + +- [#13354](https://github.com/smartcontractkit/chainlink/pull/13354) [`58d73ecf61`](https://github.com/smartcontractkit/chainlink/commit/58d73ecf618ac39c37f767e70c4e6d6a51eaba59) Thanks [@friedemannf](https://github.com/friedemannf)! - #breaking_change Remove the `xdai` `ChainType` config option. Moving forward, only `gnosis` can be used. + +- [#13221](https://github.com/smartcontractkit/chainlink/pull/13221) [`0b100ad3db`](https://github.com/smartcontractkit/chainlink/commit/0b100ad3dbf0a3c2fbd6e55c539046f6f3c9e5f6) Thanks [@ilija42](https://github.com/ilija42)! - Added a mechanism to validate forwarders for OCR2 and fallback to EOA if necessary #added + +- [#13384](https://github.com/smartcontractkit/chainlink/pull/13384) [`bc087f1de2`](https://github.com/smartcontractkit/chainlink/commit/bc087f1de2014cce1027341d14e0917c4351fb21) Thanks [@augustbleeds](https://github.com/augustbleeds)! - bump chainlink-starknet so it builds reports with median gas price #updated + +- [#13353](https://github.com/smartcontractkit/chainlink/pull/13353) [`7a86103474`](https://github.com/smartcontractkit/chainlink/commit/7a861034740a44ebb5d3f1da2d271637691c0bd3) Thanks [@pavel-raykov](https://github.com/pavel-raykov)! - #updated Remove deprecated app.shortcut links + +- [#13181](https://github.com/smartcontractkit/chainlink/pull/13181) [`c14576a945`](https://github.com/smartcontractkit/chainlink/commit/c14576a945fdc6b5099ffd31f467a0712afe6fd6) Thanks [@krehermann](https://github.com/krehermann)! - #added workflow spec auto-approval via CLO -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal remove update capabilities from capability registry +- [#13455](https://github.com/smartcontractkit/chainlink/pull/13455) [`066afc0877`](https://github.com/smartcontractkit/chainlink/commit/066afc0877a9e953bbda25a4ff09009d7f1c1e2d) Thanks [@krehermann](https://github.com/krehermann)! - #bugfix use correct internal id in workflow auto-approval + +- [#12881](https://github.com/smartcontractkit/chainlink/pull/12881) [`d675d864f0`](https://github.com/smartcontractkit/chainlink/commit/d675d864f0e6f33c783bfed17fe31b2c127eb51d) Thanks [@amit-momin](https://github.com/amit-momin)! - #added Added an auto-purge feature to the EVM TXM that identifies terminally stuck transactions either through a chain specific method or heurisitic then purges them to unblock the nonce. Included 4 new toml configs under Transactions.AutoPurge to configure this new feature: Enabled, Threshold, MinAttempts, and DetectionApiUrl. -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal add getters in capability registry +- [#13401](https://github.com/smartcontractkit/chainlink/pull/13401) [`905830c3ff`](https://github.com/smartcontractkit/chainlink/commit/905830c3ff16c670c3fbf3d83a0c2ca3a15e83a8) Thanks [@krehermann](https://github.com/krehermann)! - #db_update add persistence for DON-2-DON discovery announcements + +- [#13200](https://github.com/smartcontractkit/chainlink/pull/13200) [`4718aa7ec2`](https://github.com/smartcontractkit/chainlink/commit/4718aa7ec20e2ef70dff7fb72095d357f3725a80) Thanks [@augustbleeds](https://github.com/augustbleeds)! - Add option to include GasPriceSubunits pipeline to include gasPriceSubunits in median ocr2 transmission (only to be used with Starknet chain for now) #added #nops #updated +- [#13259](https://github.com/smartcontractkit/chainlink/pull/13259) [`76dbe19282`](https://github.com/smartcontractkit/chainlink/commit/76dbe192822c7e9f289c98e33ebb6693a07046a0) Thanks [@archseer](https://github.com/archseer)! - #added A ChainWriter implementation in the EVM relay. + +- [#13265](https://github.com/smartcontractkit/chainlink/pull/13265) [`5db47b63b3`](https://github.com/smartcontractkit/chainlink/commit/5db47b63b3f2d0addf521904940d780caf9f57eb) Thanks [@krehermann](https://github.com/krehermann)! - #db_update Add name to workflow spec. Add unique constraint to (owner,name) for workflow spec + +### Patch Changes +- [#13315](https://github.com/smartcontractkit/chainlink/pull/13315) [`3af83ed014`](https://github.com/smartcontractkit/chainlink/commit/3af83ed01439648354ac6b348d61b0f9594b99ec) Thanks [@mateusz-sekara](https://github.com/mateusz-sekara)! - Reducing the scope of 0233 migration to include only 5th word index which is required for CCIP #db_update + +- [#13144](https://github.com/smartcontractkit/chainlink/pull/13144) [`49f1bf3ba2`](https://github.com/smartcontractkit/chainlink/commit/49f1bf3ba296f0e3dfc01d5a3d371f82f159dc4a) Thanks [@jmank88](https://github.com/jmank88)! - improve handling of postgres connection settings and driver versions #db + +- [#13286](https://github.com/smartcontractkit/chainlink/pull/13286) [`6139126034`](https://github.com/smartcontractkit/chainlink/commit/61391260340ba74f3510e6ded4fdace6829630b7) Thanks [@EasterTheBunny](https://github.com/EasterTheBunny)! - enforce proper result indexing on pipeline results #breaking_change + +- [#13279](https://github.com/smartcontractkit/chainlink/pull/13279) [`5a87f4a59e`](https://github.com/smartcontractkit/chainlink/commit/5a87f4a59e3c6c92b08ebefc5090017693785729) Thanks [@DylanTinianov](https://github.com/DylanTinianov)! - #changed Remove ClientErrors interface from common - [#13230](https://github.com/smartcontractkit/chainlink/pull/13230) [`6f1ebca197`](https://github.com/smartcontractkit/chainlink/commit/6f1ebca1970d4a970be64c581800ab781c6c3c7c) Thanks [@dhaidashenko](https://github.com/dhaidashenko)! - Fixed CPU usage issues caused by inefficiencies in HeadTracker. HeadTracker's support of finality tags caused a drastic increase in the number of tracked blocks on the Arbitrum chain (from 50 to 12,000), which has led to a 30% increase in CPU usage. @@ -106,66 +143,30 @@ - [#13364](https://github.com/smartcontractkit/chainlink/pull/13364) [`fc007a9484`](https://github.com/smartcontractkit/chainlink/commit/fc007a94846c178bc9d5203dbff6b6b8c7546a71) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #bugfix fix a funding bug in LinkAvailableBalanceMonitor -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal capability registry informational findings - -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal return don capability config contract config from capability registry - -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal add capability registry comment explaining why we do not validate node operator name - -- [#13425](https://github.com/smartcontractkit/chainlink/pull/13425) [`eeb363f123`](https://github.com/smartcontractkit/chainlink/commit/eeb363f1230415dde573607a095b177c612d3bef) Thanks [@DeividasK](https://github.com/DeividasK)! - #internal - -- [#13328](https://github.com/smartcontractkit/chainlink/pull/13328) [`0d95942ad4`](https://github.com/smartcontractkit/chainlink/commit/0d95942ad414a3ecefb17bd8166fe28f474018d0) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal [Keystone] Merge version field with ID - - [#13174](https://github.com/smartcontractkit/chainlink/pull/13174) [`e778a3202b`](https://github.com/smartcontractkit/chainlink/commit/e778a3202b4d8761ffc44b790196d9a580fede1c) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #changed: AUTO-10539: adjust logging for offchain config and gas control - [#12952](https://github.com/smartcontractkit/chainlink/pull/12952) [`7572a50a78`](https://github.com/smartcontractkit/chainlink/commit/7572a50a78a270188344786937f68233df82f65b) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #added compare user-defined max gas price with current gas price in automation simulation pipeline -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal update ICapabilityConfiguration interface - - [#13216](https://github.com/smartcontractkit/chainlink/pull/13216) [`6099abbdbf`](https://github.com/smartcontractkit/chainlink/commit/6099abbdbfb3ad396ca1ed5138ecd7a13159de19) Thanks [@ibrajer](https://github.com/ibrajer)! - Added Base Sepolia to ChainUtils #changed - [#13177](https://github.com/smartcontractkit/chainlink/pull/13177) [`0d58a8d5db`](https://github.com/smartcontractkit/chainlink/commit/0d58a8d5db24f42720226e73328e501637ba59c5) Thanks [@shileiwill](https://github.com/shileiwill)! - link transfer status check #bugfix -- [#13118](https://github.com/smartcontractkit/chainlink/pull/13118) [`6008d730bf`](https://github.com/smartcontractkit/chainlink/commit/6008d730bf1fcfc4a9dd1e46497c3db75cf390fe) Thanks [@bolekk](https://github.com/bolekk)! - #internal Pass MercuryTriggerService to Mercury Transmitter - - [#13058](https://github.com/smartcontractkit/chainlink/pull/13058) [`a34a17ae9d`](https://github.com/smartcontractkit/chainlink/commit/a34a17ae9d62679a1ff15a7703f5cbcf6dfd1d0f) Thanks [@shileiwill](https://github.com/shileiwill)! - withdraw in offchain mode #bugfix -- [#13328](https://github.com/smartcontractkit/chainlink/pull/13328) [`0d95942ad4`](https://github.com/smartcontractkit/chainlink/commit/0d95942ad414a3ecefb17bd8166fe28f474018d0) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal Add workflow validation - -- [#13456](https://github.com/smartcontractkit/chainlink/pull/13456) [`b09c14d0ca`](https://github.com/smartcontractkit/chainlink/commit/b09c14d0ca85678799cb108500687d0e8456205a) Thanks [@bolekk](https://github.com/bolekk)! - #internal [Keystone] Add remote target to syncer - -- [#13176](https://github.com/smartcontractkit/chainlink/pull/13176) [`d2cd916e46`](https://github.com/smartcontractkit/chainlink/commit/d2cd916e46c51d76f7e1ea61a0cc86b1415f4036) Thanks [@ferglor](https://github.com/ferglor)! - Add logs for when the assumptions of how the log buffer will be used are violated #internal - - [#13213](https://github.com/smartcontractkit/chainlink/pull/13213) [`1b1e31ebfc`](https://github.com/smartcontractkit/chainlink/commit/1b1e31ebfc5198ab7e43291110b6f5d54e467a01) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #bugfix fix an automation smoke test flake -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal verify valid node operator when adding nodes to capability registry - -- [#13218](https://github.com/smartcontractkit/chainlink/pull/13218) [`4938ef3961`](https://github.com/smartcontractkit/chainlink/commit/4938ef396112a6de6f9822cfcc116fd5cdfb92be) Thanks [@bolekk](https://github.com/bolekk)! - #internal ReportCodec for Streams trigger - -- [#13094](https://github.com/smartcontractkit/chainlink/pull/13094) [`a0d1ce5e9c`](https://github.com/smartcontractkit/chainlink/commit/a0d1ce5e9cddc540bba8eb193865646cf0ebc0a8) Thanks [@momentmaker](https://github.com/momentmaker)! - Refactor changesets release preview workflow #internal - -- [#13175](https://github.com/smartcontractkit/chainlink/pull/13175) [`fbd94c4351`](https://github.com/smartcontractkit/chainlink/commit/fbd94c43511dabd272d7fd990dfb76de66c30a16) Thanks [@erikburt](https://github.com/erikburt)! - bump chainlink-solana dependency #internal - -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal implement remove DONs in capability registry - - [#12813](https://github.com/smartcontractkit/chainlink/pull/12813) [`ac893364e6`](https://github.com/smartcontractkit/chainlink/commit/ac893364e6c6ede08e9bf04da7dc64e0da94ab6e) Thanks [@matYang](https://github.com/matYang)! - #db_update created 2 new CCIP tables in migration 0236, one for observed gas prices, one for observed token prices; setup indexing for these tables. #added ORM for CCIP gas prices and token prices -- [#13080](https://github.com/smartcontractkit/chainlink/pull/13080) [`36cc95f625`](https://github.com/smartcontractkit/chainlink/commit/36cc95f6256b5ba418a916de2c9dc9597508147a) Thanks [@cds95](https://github.com/cds95)! - #internal Generate gethwrappers for capability registry changes - - [#13173](https://github.com/smartcontractkit/chainlink/pull/13173) [`a9717f05e9`](https://github.com/smartcontractkit/chainlink/commit/a9717f05e9af0fa07746c6b95b7f1625089a860f) Thanks [@ferglor](https://github.com/ferglor)! - Revert block number tracking #changed -- [#13453](https://github.com/smartcontractkit/chainlink/pull/13453) [`8c98c80376`](https://github.com/smartcontractkit/chainlink/commit/8c98c80376c3b6d72bffeab62ee45a74449b6ef5) Thanks [@cds95](https://github.com/cds95)! - #internal update error message when node does not exist - - [#12952](https://github.com/smartcontractkit/chainlink/pull/12952) [`7572a50a78`](https://github.com/smartcontractkit/chainlink/commit/7572a50a78a270188344786937f68233df82f65b) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #added pass a gas estimator to registry 2.1 pipeline -- [#13128](https://github.com/smartcontractkit/chainlink/pull/13128) [`a0e7b7cdd6`](https://github.com/smartcontractkit/chainlink/commit/a0e7b7cdd63ecb3f4d8e0ca3f5a4111703760c9b) Thanks [@samsondav](https://github.com/samsondav)! - #internal improve mercury tranmission debugging - - [#13132](https://github.com/smartcontractkit/chainlink/pull/13132) [`eed5668e3c`](https://github.com/smartcontractkit/chainlink/commit/eed5668e3c83cb680d2915f89d097fcb1b74a4f9) Thanks [@akuzni2](https://github.com/akuzni2)! - #nops fix metric description on mercury_transmit_queue_load - [#13084](https://github.com/smartcontractkit/chainlink/pull/13084) [`d79bdf16c5`](https://github.com/smartcontractkit/chainlink/commit/d79bdf16c5129cf7bc7cc5114f92eb07fd3fbf02) Thanks [@austinborn](https://github.com/austinborn)! - #updated Add gethwrappers for operatorforwarder contracts @@ -176,56 +177,20 @@ - [#13133](https://github.com/smartcontractkit/chainlink/pull/13133) [`2e668372ac`](https://github.com/smartcontractkit/chainlink/commit/2e668372ac54e71fd357feba427ffacf0613bda2) Thanks [@matYang](https://github.com/matYang)! - #changed CCIP price cache to use DB timestamp -- [#13380](https://github.com/smartcontractkit/chainlink/pull/13380) [`21c4cde066`](https://github.com/smartcontractkit/chainlink/commit/21c4cde066f3d6a49072ca338c966265b910583e) Thanks [@dimriou](https://github.com/dimriou)! - Removed deprecated evm client code #internal - - [#13096](https://github.com/smartcontractkit/chainlink/pull/13096) [`2c08c8c1a5`](https://github.com/smartcontractkit/chainlink/commit/2c08c8c1a58ea4b7c09b0d5a5ca3b8a677beb9f4) Thanks [@shileiwill](https://github.com/shileiwill)! - add upkeepCharged event #bugfix -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal verify that node is not part of a DON when removing - -- [#13202](https://github.com/smartcontractkit/chainlink/pull/13202) [`eb6b50d313`](https://github.com/smartcontractkit/chainlink/commit/eb6b50d31323c324aaa2bf8d1cf465f97a7893fd) Thanks [@bolekk](https://github.com/bolekk)! - #internal [Keystone] EVM encoder support for tuples - - [#13078](https://github.com/smartcontractkit/chainlink/pull/13078) [`0917394a46`](https://github.com/smartcontractkit/chainlink/commit/0917394a4625c3e97b17e348dd473199a15402bf) Thanks [@finleydecker](https://github.com/finleydecker)! - bumpThreshold config setting for chains using suggestPrice estimator #updated -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal remove tracking deprecated arrays - -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal capability registry internal review - - [#13336](https://github.com/smartcontractkit/chainlink/pull/13336) [`4c7e5a0efa`](https://github.com/smartcontractkit/chainlink/commit/4c7e5a0efa90aed5d5454b5a68753076eea67f55) Thanks [@dhaidashenko](https://github.com/dhaidashenko)! - Added config option `HeadTracker.FinalityTagBypass` to force `HeadTracker` to track blocks up to `FinalityDepth` even if `FinalityTagsEnabled = true`. This option is a temporary measure to address high CPU usage on chains with extremely large actual finality depth (gap between the current head and the latest finalized block). #added Added config option `HeadTracker.MaxAllowedFinalityDepth` maximum gap between current head to the latest finalized block that `HeadTracker` considers healthy. #added -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal internal-review-fixes-for-capability-registry - -- [#13199](https://github.com/smartcontractkit/chainlink/pull/13199) [`4f502c9fd0`](https://github.com/smartcontractkit/chainlink/commit/4f502c9fd0fea458647bb345f5c0da995f3b6cb1) Thanks [@bolekk](https://github.com/bolekk)! - #internal Use Aggregator factory for OCR capability - - [#13263](https://github.com/smartcontractkit/chainlink/pull/13263) [`14ec6c4a91`](https://github.com/smartcontractkit/chainlink/commit/14ec6c4a912eeb65753703c363d1e90cbcf88328) Thanks [@shileiwill](https://github.com/shileiwill)! - tune debugging script #bugfix - [#13088](https://github.com/smartcontractkit/chainlink/pull/13088) [`29b16360fb`](https://github.com/smartcontractkit/chainlink/commit/29b16360fb41e4372f72fe744aaf3ee8234a9b67) Thanks [@shileiwill](https://github.com/shileiwill)! - get available erc20 for payment #bugfix - [#13165](https://github.com/smartcontractkit/chainlink/pull/13165) [`143741012c`](https://github.com/smartcontractkit/chainlink/commit/143741012c4d0b148ada9d5aa237ff932cd3005b) Thanks [@cedric-cordenier](https://github.com/cedric-cordenier)! - #db_update Add ON DELETE CASCADE to workflow tables -- [#13103](https://github.com/smartcontractkit/chainlink/pull/13103) [`54f7c9c8f5`](https://github.com/smartcontractkit/chainlink/commit/54f7c9c8f5508d0d0a063eb435404b4164723300) Thanks [@DeividasK](https://github.com/DeividasK)! - #internal regen geth wrappers for capability registry - -- [#13112](https://github.com/smartcontractkit/chainlink/pull/13112) [`80590662bd`](https://github.com/smartcontractkit/chainlink/commit/80590662bd9956d3c93449ca4703a2430e0613b7) Thanks [@HenryNguyen5](https://github.com/HenryNguyen5)! - #internal Normalize keystone workflow ref regex property to match id regex - -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal track config count in DON struct - -- [#13102](https://github.com/smartcontractkit/chainlink/pull/13102) [`700a827194`](https://github.com/smartcontractkit/chainlink/commit/700a82719451611381ab5dbb94fe00547660440b) Thanks [@cds95](https://github.com/cds95)! - #internal generate geth wrappers for capability registry remove nodes - -- [#13406](https://github.com/smartcontractkit/chainlink/pull/13406) [`a63569c9a3`](https://github.com/smartcontractkit/chainlink/commit/a63569c9a3893a7dc431459e08a4b08bb3a91231) Thanks [@bolekk](https://github.com/bolekk)! - #internal #bugfix Fix target wrapper init problems - -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal allow updating capabilities and to add/remove multiple capabilities at once from the capability registry - -- [#13189](https://github.com/smartcontractkit/chainlink/pull/13189) [`1451b2b632`](https://github.com/smartcontractkit/chainlink/commit/1451b2b6321f997c2df2c0b7fd05d6ba1eac30e4) Thanks [@samsondav](https://github.com/samsondav)! - Performance improvements for mercury single insert for multiple mercury servers #internal - -- [#13366](https://github.com/smartcontractkit/chainlink/pull/13366) [`d53d6d08da`](https://github.com/smartcontractkit/chainlink/commit/d53d6d08dac5d3ee27ae89012669c6c2455295c8) Thanks [@bolekk](https://github.com/bolekk)! - #internal keystone report context - -- [#13389](https://github.com/smartcontractkit/chainlink/pull/13389) [`3959091d4f`](https://github.com/smartcontractkit/chainlink/commit/3959091d4f3925b64cb6b0b55b7f7c72a4f924b9) Thanks [@bolekk](https://github.com/bolekk)! - #internal Update metadata passed to Forwarder and Receiver - -- [#13183](https://github.com/smartcontractkit/chainlink/pull/13183) [`96304756a7`](https://github.com/smartcontractkit/chainlink/commit/96304756a77cdb2acf251d21d59b6aa8b55bf61a) Thanks [@cds95](https://github.com/cds95)! - #internal update node signer type - -- [#13368](https://github.com/smartcontractkit/chainlink/pull/13368) [`000f2cb36b`](https://github.com/smartcontractkit/chainlink/commit/000f2cb36b7d9b6d046d383c85996ae1ae7a606e) Thanks [@cds95](https://github.com/cds95)! - #internal update uint256 to uint32 for donId declaration in capability config interface - - [#12952](https://github.com/smartcontractkit/chainlink/pull/12952) [`7572a50a78`](https://github.com/smartcontractkit/chainlink/commit/7572a50a78a270188344786937f68233df82f65b) Thanks [@FelixFan1992](https://github.com/FelixFan1992)! - #added an integration test for max gas price check - [#13272](https://github.com/smartcontractkit/chainlink/pull/13272) [`c7a6356f49`](https://github.com/smartcontractkit/chainlink/commit/c7a6356f4903e919964ca91493f18e0ebf4eb08b) Thanks [@friedemannf](https://github.com/friedemannf)! - #bugfix allow ChainType to be set to xdai diff --git a/GNUmakefile b/GNUmakefile index 711a41840a9..8353a288e87 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -135,7 +135,7 @@ gomods: ## Install gomods .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.42.2 + go install github.com/vektra/mockery/v2@v2.43.2 .PHONY: codecgen codecgen: $(codecgen) ## Install codecgen @@ -179,6 +179,10 @@ goreleaser-dev-release: ## run goreleaser snapshot release modgraph: ./tools/bin/modgraph > go.md +.PHONY: test-short +test-short: ## Run 'go test -short' and suppress uninteresting output + go test -short ./... | grep -v "[no test files]" | grep -v "\(cached\)" + help: @echo "" @echo " .__ .__ .__ .__ __" diff --git a/common/client/ctx.go b/common/client/ctx.go new file mode 100644 index 00000000000..57b2fc8a866 --- /dev/null +++ b/common/client/ctx.go @@ -0,0 +1,17 @@ +package client + +import "context" + +type multiNodeContextKey int + +const ( + contextKeyHeathCheckRequest multiNodeContextKey = iota + 1 +) + +func CtxAddHealthCheckFlag(ctx context.Context) context.Context { + return context.WithValue(ctx, contextKeyHeathCheckRequest, struct{}{}) +} + +func CtxIsHeathCheckRequest(ctx context.Context) bool { + return ctx.Value(contextKeyHeathCheckRequest) != nil +} diff --git a/common/client/ctx_test.go b/common/client/ctx_test.go new file mode 100644 index 00000000000..822b36c3f81 --- /dev/null +++ b/common/client/ctx_test.go @@ -0,0 +1,16 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" +) + +func TestContext(t *testing.T) { + ctx := tests.Context(t) + assert.False(t, CtxIsHeathCheckRequest(ctx), "expected false for test context") + ctx = CtxAddHealthCheckFlag(ctx) + assert.True(t, CtxIsHeathCheckRequest(ctx), "expected context to contain the healthcheck flag") +} diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index 9a66e164aa0..64c6dbcb0a8 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index ec83158a5ff..a7c0e4dbdb8 100644 --- a/common/client/mock_node_client_test.go +++ b/common/client/mock_node_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client @@ -116,6 +116,34 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) DisconnectAll() { _m.Called() } +// GetInterceptedChainInfo provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) GetInterceptedChainInfo() (ChainInfo, ChainInfo) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetInterceptedChainInfo") + } + + var r0 ChainInfo + var r1 ChainInfo + if rf, ok := ret.Get(0).(func() (ChainInfo, ChainInfo)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() ChainInfo); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(ChainInfo) + } + + if rf, ok := ret.Get(1).(func() ChainInfo); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(ChainInfo) + } + + return r0, r1 +} + // 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) @@ -177,32 +205,29 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) SetAliveLoopSub(_a0 types.Subscription _m.Called(_a0) } -// Subscribe provides a mock function with given fields: ctx, channel, args -func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) { - var _ca []interface{} - _ca = append(_ca, ctx, channel) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) +// SubscribeNewHead provides a mock function with given fields: ctx, channel +func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (types.Subscription, error) { + ret := _m.Called(ctx, channel) if len(ret) == 0 { - panic("no return value specified for Subscribe") + panic("no return value specified for SubscribeNewHead") } var r0 types.Subscription var r1 error - if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { - return rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD) (types.Subscription, error)); ok { + return rf(ctx, channel) } - if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) types.Subscription); ok { - r0 = rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD) types.Subscription); ok { + r0 = rf(ctx, channel) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(types.Subscription) } } - if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD, ...interface{}) error); ok { - r1 = rf(ctx, channel, args...) + if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD) error); ok { + r1 = rf(ctx, channel) } else { r1 = ret.Error(1) } diff --git a/common/client/mock_node_selector_test.go b/common/client/mock_node_selector_test.go index 996d064daa4..783fc50c290 100644 --- a/common/client/mock_node_selector_test.go +++ b/common/client/mock_node_selector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go index ee2cacb9274..5109eb6bb90 100644 --- a/common/client/mock_node_test.go +++ b/common/client/mock_node_test.go @@ -1,14 +1,12 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client import ( context "context" - big "math/big" - - mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" ) // mockNode is an autogenerated mock type for the Node type @@ -52,6 +50,24 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { return r0 } +// HighestUserObservations provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) HighestUserObservations() ChainInfo { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for HighestUserObservations") + } + + var r0 ChainInfo + if rf, ok := ret.Get(0).(func() ChainInfo); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(ChainInfo) + } + + return r0 +} + // Name provides a mock function with given fields: func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { ret := _m.Called() @@ -106,6 +122,11 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { return r0 } +// SetPoolChainInfoProvider provides a mock function with given fields: _a0 +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) SetPoolChainInfoProvider(_a0 PoolChainInfoProvider) { + _m.Called(_a0) +} + // Start provides a mock function with given fields: _a0 func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { ret := _m.Called(_a0) @@ -143,7 +164,7 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { } // StateAndLatest provides a mock function with given fields: -func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, ChainInfo) { ret := _m.Called() if len(ret) == 0 { @@ -151,9 +172,8 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *bi } var r0 nodeState - var r1 int64 - var r2 *big.Int - if rf, ok := ret.Get(0).(func() (nodeState, int64, *big.Int)); ok { + var r1 ChainInfo + if rf, ok := ret.Get(0).(func() (nodeState, ChainInfo)); ok { return rf() } if rf, ok := ret.Get(0).(func() nodeState); ok { @@ -162,21 +182,13 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *bi r0 = ret.Get(0).(nodeState) } - if rf, ok := ret.Get(1).(func() int64); ok { + if rf, ok := ret.Get(1).(func() ChainInfo); ok { r1 = rf() } else { - r1 = ret.Get(1).(int64) - } - - if rf, ok := ret.Get(2).(func() *big.Int); ok { - r2 = rf() - } else { - if ret.Get(2) != nil { - r2 = ret.Get(2).(*big.Int) - } + r1 = ret.Get(1).(ChainInfo) } - return r0, r1, r2 + return r0, r1 } // String provides a mock function with given fields: diff --git a/common/client/mock_pool_chain_info_provider_test.go b/common/client/mock_pool_chain_info_provider_test.go new file mode 100644 index 00000000000..4e4955e7381 --- /dev/null +++ b/common/client/mock_pool_chain_info_provider_test.go @@ -0,0 +1,70 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package client + +import mock "github.com/stretchr/testify/mock" + +// mockPoolChainInfoProvider is an autogenerated mock type for the PoolChainInfoProvider type +type mockPoolChainInfoProvider struct { + mock.Mock +} + +// HighestUserObservations provides a mock function with given fields: +func (_m *mockPoolChainInfoProvider) HighestUserObservations() ChainInfo { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for HighestUserObservations") + } + + var r0 ChainInfo + if rf, ok := ret.Get(0).(func() ChainInfo); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(ChainInfo) + } + + return r0 +} + +// LatestChainInfo provides a mock function with given fields: +func (_m *mockPoolChainInfoProvider) LatestChainInfo() (int, ChainInfo) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for LatestChainInfo") + } + + var r0 int + var r1 ChainInfo + if rf, ok := ret.Get(0).(func() (int, ChainInfo)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func() ChainInfo); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(ChainInfo) + } + + return r0, r1 +} + +// newMockPoolChainInfoProvider creates a new instance of mockPoolChainInfoProvider. 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 newMockPoolChainInfoProvider(t interface { + mock.TestingT + Cleanup(func()) +}) *mockPoolChainInfoProvider { + mock := &mockPoolChainInfoProvider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index 54f57e81f65..81bac04547d 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client @@ -366,6 +366,34 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS return r0, r1 } +// GetInterceptedChainInfo provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) GetInterceptedChainInfo() (ChainInfo, ChainInfo) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetInterceptedChainInfo") + } + + var r0 ChainInfo + var r1 ChainInfo + if rf, ok := ret.Get(0).(func() (ChainInfo, ChainInfo)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() ChainInfo); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(ChainInfo) + } + + if rf, ok := ret.Get(1).(func() ChainInfo); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(ChainInfo) + } + + 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) @@ -637,32 +665,29 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS return r0 } -// Subscribe provides a mock function with given fields: ctx, channel, args -func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) { - var _ca []interface{} - _ca = append(_ca, ctx, channel) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) +// SubscribeNewHead provides a mock function with given fields: ctx, channel +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (types.Subscription, error) { + ret := _m.Called(ctx, channel) if len(ret) == 0 { - panic("no return value specified for Subscribe") + panic("no return value specified for SubscribeNewHead") } var r0 types.Subscription var r1 error - if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { - return rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD) (types.Subscription, error)); ok { + return rf(ctx, channel) } - if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) types.Subscription); ok { - r0 = rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD) types.Subscription); ok { + r0 = rf(ctx, channel) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(types.Subscription) } } - if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD, ...interface{}) error); ok { - r1 = rf(ctx, channel, args...) + if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD) error); ok { + r1 = rf(ctx, channel) } else { r1 = ret.Error(1) } diff --git a/common/client/mock_send_only_client_test.go b/common/client/mock_send_only_client_test.go index b07e10ed8ce..606506e657a 100644 --- a/common/client/mock_send_only_client_test.go +++ b/common/client/mock_send_only_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client diff --git a/common/client/mock_send_only_node_test.go b/common/client/mock_send_only_node_test.go index 4822c2620b8..a39df992aef 100644 --- a/common/client/mock_send_only_node_test.go +++ b/common/client/mock_send_only_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package client diff --git a/common/client/mocks/config.go b/common/client/mocks/config.go index 306965a9f5d..d1007f39f0f 100644 --- a/common/client/mocks/config.go +++ b/common/client/mocks/config.go @@ -3,9 +3,10 @@ package mocks import "time" type ChainConfig struct { - IsFinalityTagEnabled bool - FinalityDepthVal uint32 - NoNewHeadsThresholdVal time.Duration + IsFinalityTagEnabled bool + FinalityDepthVal uint32 + NoNewHeadsThresholdVal time.Duration + FinalizedBlockOffsetVal uint32 } func (t ChainConfig) NodeNoNewHeadsThreshold() time.Duration { @@ -19,3 +20,7 @@ func (t ChainConfig) FinalityDepth() uint32 { func (t ChainConfig) FinalityTagEnabled() bool { return t.IsFinalityTagEnabled } + +func (t ChainConfig) FinalizedBlockOffset() uint32 { + return t.FinalizedBlockOffsetVal +} diff --git a/common/client/multi_node.go b/common/client/multi_node.go index 0fc095c2931..4d4ea925fe8 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -15,8 +15,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -90,18 +88,19 @@ type multiNode[ BATCH_ELEM any, ] struct { services.StateMachine - nodes []Node[CHAIN_ID, HEAD, RPC_CLIENT] - sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] - chainID CHAIN_ID - lggr logger.SugaredLogger - selectionMode string - noNewHeadsThreshold time.Duration - nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] - leaseDuration time.Duration - leaseTicker *time.Ticker - chainFamily string - reportInterval time.Duration - sendTxSoftTimeout time.Duration // defines max waiting time from first response til responses evaluation + nodes []Node[CHAIN_ID, HEAD, RPC_CLIENT] + sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] + chainID CHAIN_ID + lggr logger.SugaredLogger + selectionMode string + noNewHeadsThreshold time.Duration + nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] + leaseDuration time.Duration + leaseTicker *time.Ticker + chainFamily string + reportInterval time.Duration + deathDeclarationDelay time.Duration + sendTxSoftTimeout time.Duration // defines max waiting time from first response til responses evaluation activeMu sync.RWMutex activeNode Node[CHAIN_ID, HEAD, RPC_CLIENT] @@ -137,6 +136,7 @@ func NewMultiNode[ chainFamily string, classifySendTxError func(tx TX, err error) SendTxReturnCode, sendTxSoftTimeout time.Duration, + deathDeclarationDelay time.Duration, ) MultiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM] { nodeSelector := newNodeSelector(selectionMode, nodes) // Prometheus' default interval is 15s, set this to under 7.5s to avoid @@ -146,19 +146,20 @@ func NewMultiNode[ sendTxSoftTimeout = QueryTimeout / 2 } c := &multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]{ - nodes: nodes, - sendonlys: sendonlys, - chainID: chainID, - lggr: logger.Sugared(lggr).Named("MultiNode").With("chainID", chainID.String()), - selectionMode: selectionMode, - noNewHeadsThreshold: noNewHeadsThreshold, - nodeSelector: nodeSelector, - chStop: make(services.StopChan), - leaseDuration: leaseDuration, - chainFamily: chainFamily, - classifySendTxError: classifySendTxError, - reportInterval: reportInterval, - sendTxSoftTimeout: sendTxSoftTimeout, + nodes: nodes, + sendonlys: sendonlys, + chainID: chainID, + lggr: logger.Sugared(lggr).Named("MultiNode").With("chainID", chainID.String()), + selectionMode: selectionMode, + noNewHeadsThreshold: noNewHeadsThreshold, + nodeSelector: nodeSelector, + chStop: make(services.StopChan), + leaseDuration: leaseDuration, + chainFamily: chainFamily, + classifySendTxError: classifySendTxError, + reportInterval: reportInterval, + deathDeclarationDelay: deathDeclarationDelay, + sendTxSoftTimeout: sendTxSoftTimeout, } c.lggr.Debugf("The MultiNode is configured to use NodeSelectionMode: %s", selectionMode) @@ -180,14 +181,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP if n.ConfiguredChainID().String() != c.chainID.String() { return ms.CloseBecause(fmt.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) } - rawNode, ok := n.(*node[CHAIN_ID, HEAD, RPC_CLIENT]) - if ok { - // This is a bit hacky but it allows the node to be aware of - // pool state and prevent certain state transitions that might - // otherwise leave no nodes available. It is better to have one - // node in a degraded state than no nodes at all. - rawNode.nLiveNodes = c.nLiveNodes - } + n.SetPoolChainInfoProvider(c) // node will handle its own redialing and automatic recovery if err := ms.Start(ctx, n); err != nil { return err @@ -253,6 +247,9 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP return // another goroutine beat us here } + if c.activeNode != nil { + c.activeNode.UnsubscribeAllExceptAliveLoop() + } c.activeNode = c.nodeSelector.Select() if c.activeNode == nil { @@ -265,22 +262,37 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP return c.activeNode, err } -// nLiveNodes returns the number of currently alive nodes, as well as the highest block number and greatest total difficulty. -// totalDifficulty will be 0 if all nodes return nil. -func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty *big.Int) { - totalDifficulty = big.NewInt(0) +// LatestChainInfo - returns number of live nodes available in the pool, so we can prevent the last alive node in a pool from being marked as out-of-sync. +// Return highest ChainInfo most recently received by the alive nodes. +// E.g. If Node A's the most recent block is 10 and highest 15 and for Node B it's - 12 and 14. This method will return 12. +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) LatestChainInfo() (int, ChainInfo) { + var nLiveNodes int + ch := ChainInfo{ + TotalDifficulty: big.NewInt(0), + } for _, n := range c.nodes { - if s, num, td := n.StateAndLatest(); s == nodeStateAlive { + if s, nodeChainInfo := n.StateAndLatest(); s == nodeStateAlive { nLiveNodes++ - if num > blockNumber { - blockNumber = num - } - if td != nil && td.Cmp(totalDifficulty) > 0 { - totalDifficulty = td - } + ch.BlockNumber = max(ch.BlockNumber, nodeChainInfo.BlockNumber) + ch.FinalizedBlockNumber = max(ch.FinalizedBlockNumber, nodeChainInfo.FinalizedBlockNumber) + ch.TotalDifficulty = MaxTotalDifficulty(ch.TotalDifficulty, nodeChainInfo.TotalDifficulty) } } - return + return nLiveNodes, ch +} + +// HighestUserObservations - returns highest ChainInfo ever observed by any user of the MultiNode +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) HighestUserObservations() ChainInfo { + ch := ChainInfo{ + TotalDifficulty: big.NewInt(0), + } + for _, n := range c.nodes { + nodeChainInfo := n.HighestUserObservations() + ch.BlockNumber = max(ch.BlockNumber, nodeChainInfo.BlockNumber) + ch.FinalizedBlockNumber = max(ch.FinalizedBlockNumber, nodeChainInfo.FinalizedBlockNumber) + ch.TotalDifficulty = MaxTotalDifficulty(ch.TotalDifficulty, nodeChainInfo.TotalDifficulty) + } + return ch } func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) checkLease() { @@ -295,10 +307,13 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } c.activeMu.Lock() + defer c.activeMu.Unlock() if bestNode != c.activeNode { + if c.activeNode != nil { + c.activeNode.UnsubscribeAllExceptAliveLoop() + } c.activeNode = bestNode } - c.activeMu.Unlock() } func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) checkLeaseLoop() { @@ -319,52 +334,71 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) runLoop() { defer c.wg.Done() - c.report() + nodeStates := make([]nodeWithState, len(c.nodes)) + for i, n := range c.nodes { + nodeStates[i] = nodeWithState{ + Node: n.String(), + State: n.State().String(), + DeadSince: nil, + } + } + + c.report(nodeStates) - monitor := time.NewTicker(utils.WithJitter(c.reportInterval)) + monitor := services.NewTicker(c.reportInterval) defer monitor.Stop() for { select { case <-monitor.C: - c.report() + c.report(nodeStates) case <-c.chStop: return } } } -func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) report() { - type nodeWithState struct { - Node string - State string - } +type nodeWithState struct { + Node string + State string + DeadSince *time.Time +} - var total, dead int +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) report(nodesStateInfo []nodeWithState) { + start := time.Now() + var dead int counts := make(map[nodeState]int) - nodeStates := make([]nodeWithState, len(c.nodes)) for i, n := range c.nodes { state := n.State() - nodeStates[i] = nodeWithState{n.String(), state.String()} - total++ - if state != nodeStateAlive { + counts[state]++ + nodesStateInfo[i].State = state.String() + if state == nodeStateAlive { + nodesStateInfo[i].DeadSince = nil + continue + } + + if nodesStateInfo[i].DeadSince == nil { + nodesStateInfo[i].DeadSince = &start + } + + if start.Sub(*nodesStateInfo[i].DeadSince) >= c.deathDeclarationDelay { dead++ } - counts[state]++ } for _, state := range allNodeStates { count := counts[state] PromMultiNodeRPCNodeStates.WithLabelValues(c.chainFamily, c.chainID.String(), state.String()).Set(float64(count)) } + total := len(c.nodes) live := total - dead - c.lggr.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + c.lggr.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodesStateInfo) if total == dead { rerr := fmt.Errorf("no primary nodes available: 0/%d nodes are alive", total) - c.lggr.Criticalw(rerr.Error(), "nodeStates", nodeStates) + c.lggr.Criticalw(rerr.Error(), "nodeStates", nodesStateInfo) c.SvcErrBuffer.Append(rerr) } else if dead > 0 { - c.lggr.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + c.lggr.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodesStateInfo) } } @@ -779,12 +813,12 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP return n.RPC().SimulateTransaction(ctx, tx) } -func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (s types.Subscription, err error) { +func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (s types.Subscription, err error) { n, err := c.selectNode() if err != nil { return s, err } - return n.RPC().Subscribe(ctx, channel, args...) + return n.RPC().SubscribeNewHead(ctx, channel) } func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) TokenBalance(ctx context.Context, account ADDR, tokenAddr ADDR) (b *big.Int, err error) { diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 3076d99b618..ffef0c29d56 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -29,16 +29,17 @@ type testMultiNode struct { } type multiNodeOpts struct { - logger logger.Logger - selectionMode string - leaseDuration time.Duration - noNewHeadsThreshold time.Duration - nodes []Node[types.ID, types.Head[Hashable], multiNodeRPCClient] - sendonlys []SendOnlyNode[types.ID, multiNodeRPCClient] - chainID types.ID - chainFamily string - classifySendTxError func(tx any, err error) SendTxReturnCode - sendTxSoftTimeout time.Duration + logger logger.Logger + selectionMode string + leaseDuration time.Duration + noNewHeadsThreshold time.Duration + nodes []Node[types.ID, types.Head[Hashable], multiNodeRPCClient] + sendonlys []SendOnlyNode[types.ID, multiNodeRPCClient] + chainID types.ID + chainFamily string + classifySendTxError func(tx any, err error) SendTxReturnCode + sendTxSoftTimeout time.Duration + deathDeclarationDelay time.Duration } func newTestMultiNode(t *testing.T, opts multiNodeOpts) testMultiNode { @@ -49,7 +50,7 @@ func newTestMultiNode(t *testing.T, opts multiNodeOpts) testMultiNode { result := NewMultiNode[types.ID, *big.Int, Hashable, Hashable, any, Hashable, any, any, types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient, any](opts.logger, opts.selectionMode, opts.leaseDuration, opts.noNewHeadsThreshold, opts.nodes, opts.sendonlys, - opts.chainID, opts.chainFamily, opts.classifySendTxError, opts.sendTxSoftTimeout) + opts.chainID, opts.chainFamily, opts.classifySendTxError, opts.sendTxSoftTimeout, opts.deathDeclarationDelay) return testMultiNode{ result.(*multiNode[types.ID, *big.Int, Hashable, Hashable, any, Hashable, any, any, types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient, any]), @@ -67,14 +68,21 @@ func newHealthyNode(t *testing.T, chainID types.ID) *mockNode[types.ID, types.He } func newNodeWithState(t *testing.T, chainID types.ID, state nodeState) *mockNode[types.ID, types.Head[Hashable], multiNodeRPCClient] { + node := newDialableNode(t, chainID) + node.On("State").Return(state).Maybe() + return node +} + +func newDialableNode(t *testing.T, chainID types.ID) *mockNode[types.ID, types.Head[Hashable], multiNodeRPCClient] { node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) node.On("ConfiguredChainID").Return(chainID).Once() node.On("Start", mock.Anything).Return(nil).Once() node.On("Close").Return(nil).Once() - node.On("State").Return(state).Maybe() node.On("String").Return(fmt.Sprintf("healthy_node_%d", rand.Int())).Maybe() + node.On("SetPoolChainInfoProvider", mock.Anything).Once() return node } + func TestMultiNode_Dial(t *testing.T) { t.Parallel() @@ -111,6 +119,7 @@ func TestMultiNode_Dial(t *testing.T) { node := newMockNode(t) chainID := types.RandomID() node.On("ConfiguredChainID").Return(chainID).Once() + node.On("SetPoolChainInfoProvider", mock.Anything).Once() expectedError := errors.New("failed to start node") node.On("Start", mock.Anything).Return(expectedError).Once() mn := newTestMultiNode(t, multiNodeOpts{ @@ -128,6 +137,7 @@ func TestMultiNode_Dial(t *testing.T) { node1 := newHealthyNode(t, chainID) node2 := newMockNode(t) node2.On("ConfiguredChainID").Return(chainID).Once() + node2.On("SetPoolChainInfoProvider", mock.Anything).Once() expectedError := errors.New("failed to start node") node2.On("Start", mock.Anything).Return(expectedError).Once() @@ -219,6 +229,7 @@ func TestMultiNode_Report(t *testing.T) { logger: lggr, }) mn.reportInterval = tests.TestInterval + mn.deathDeclarationDelay = tests.TestInterval defer func() { assert.NoError(t, mn.Close()) }() err := mn.Dial(tests.Context(t)) require.NoError(t, err) @@ -236,6 +247,7 @@ func TestMultiNode_Report(t *testing.T) { logger: lggr, }) mn.reportInterval = tests.TestInterval + mn.deathDeclarationDelay = tests.TestInterval defer func() { assert.NoError(t, mn.Close()) }() err := mn.Dial(tests.Context(t)) require.NoError(t, err) @@ -377,6 +389,7 @@ func TestMultiNode_selectNode(t *testing.T) { chainID := types.RandomID() oldBest := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) oldBest.On("String").Return("oldBest").Maybe() + oldBest.On("UnsubscribeAllExceptAliveLoop").Once() newBest := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) newBest.On("String").Return("newBest").Maybe() mn := newTestMultiNode(t, multiNodeOpts{ @@ -417,49 +430,94 @@ func TestMultiNode_selectNode(t *testing.T) { }) } -func TestMultiNode_nLiveNodes(t *testing.T) { +func TestMultiNode_ChainInfo(t *testing.T) { t.Parallel() type nodeParams struct { - BlockNumber int64 - TotalDifficulty *big.Int - State nodeState + LatestChainInfo ChainInfo + HighestUserObservations ChainInfo + State nodeState } testCases := []struct { - Name string - ExpectedNLiveNodes int - ExpectedBlockNumber int64 - ExpectedTotalDifficulty *big.Int - NodeParams []nodeParams + Name string + ExpectedNLiveNodes int + ExpectedLatestChainInfo ChainInfo + ExpectedHighestUserObservations ChainInfo + NodeParams []nodeParams }{ { - Name: "no nodes", - ExpectedTotalDifficulty: big.NewInt(0), + Name: "no nodes", + ExpectedLatestChainInfo: ChainInfo{ + TotalDifficulty: big.NewInt(0), + }, + ExpectedHighestUserObservations: ChainInfo{ + TotalDifficulty: big.NewInt(0), + }, }, { - Name: "Best node is not healthy", - ExpectedTotalDifficulty: big.NewInt(10), - ExpectedBlockNumber: 20, - ExpectedNLiveNodes: 3, + Name: "Best node is not healthy", + ExpectedNLiveNodes: 3, + ExpectedLatestChainInfo: ChainInfo{ + BlockNumber: 20, + FinalizedBlockNumber: 10, + TotalDifficulty: big.NewInt(10), + }, + ExpectedHighestUserObservations: ChainInfo{ + BlockNumber: 1005, + FinalizedBlockNumber: 995, + TotalDifficulty: big.NewInt(2005), + }, NodeParams: []nodeParams{ { - State: nodeStateOutOfSync, - BlockNumber: 1000, - TotalDifficulty: big.NewInt(2000), + State: nodeStateOutOfSync, + LatestChainInfo: ChainInfo{ + BlockNumber: 1000, + FinalizedBlockNumber: 990, + TotalDifficulty: big.NewInt(2000), + }, + HighestUserObservations: ChainInfo{ + BlockNumber: 1005, + FinalizedBlockNumber: 995, + TotalDifficulty: big.NewInt(2005), + }, }, { - State: nodeStateAlive, - BlockNumber: 20, - TotalDifficulty: big.NewInt(9), + State: nodeStateAlive, + LatestChainInfo: ChainInfo{ + BlockNumber: 20, + FinalizedBlockNumber: 10, + TotalDifficulty: big.NewInt(9), + }, + HighestUserObservations: ChainInfo{ + BlockNumber: 25, + FinalizedBlockNumber: 15, + TotalDifficulty: big.NewInt(14), + }, }, { - State: nodeStateAlive, - BlockNumber: 19, - TotalDifficulty: big.NewInt(10), + State: nodeStateAlive, + LatestChainInfo: ChainInfo{ + BlockNumber: 19, + FinalizedBlockNumber: 9, + TotalDifficulty: big.NewInt(10), + }, + HighestUserObservations: ChainInfo{ + BlockNumber: 24, + FinalizedBlockNumber: 14, + TotalDifficulty: big.NewInt(15), + }, }, { - State: nodeStateAlive, - BlockNumber: 11, - TotalDifficulty: nil, + State: nodeStateAlive, + LatestChainInfo: ChainInfo{ + BlockNumber: 11, + FinalizedBlockNumber: 1, + TotalDifficulty: nil, + }, + HighestUserObservations: ChainInfo{ + BlockNumber: 16, + FinalizedBlockNumber: 6, + TotalDifficulty: nil, + }, }, }, }, @@ -475,14 +533,17 @@ func TestMultiNode_nLiveNodes(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { for _, params := range tc.NodeParams { node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) - node.On("StateAndLatest").Return(params.State, params.BlockNumber, params.TotalDifficulty) + node.On("StateAndLatest").Return(params.State, params.LatestChainInfo) + node.On("HighestUserObservations").Return(params.HighestUserObservations) mn.nodes = append(mn.nodes, node) } - nNodes, blockNum, td := mn.nLiveNodes() + nNodes, latestChainInfo := mn.LatestChainInfo() assert.Equal(t, tc.ExpectedNLiveNodes, nNodes) - assert.Equal(t, tc.ExpectedTotalDifficulty, td) - assert.Equal(t, tc.ExpectedBlockNumber, blockNum) + assert.Equal(t, tc.ExpectedLatestChainInfo, latestChainInfo) + + highestChainInfo := mn.HighestUserObservations() + assert.Equal(t, tc.ExpectedHighestUserObservations, highestChainInfo) }) } } diff --git a/common/client/node.go b/common/client/node.go index 869ea89c039..7871c622eb4 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "math/big" "net/url" "sync" "time" @@ -44,12 +43,15 @@ type NodeConfig interface { SyncThreshold() uint32 NodeIsSyncingEnabled() bool FinalizedBlockPollInterval() time.Duration + EnforceRepeatableRead() bool + DeathDeclarationDelay() time.Duration } type ChainConfig interface { NodeNoNewHeadsThreshold() time.Duration FinalityDepth() uint32 FinalityTagEnabled() bool + FinalizedBlockOffset() uint32 } //go:generate mockery --quiet --name Node --structname mockNode --filename "mock_node_test.go" --inpackage --case=underscore @@ -58,15 +60,21 @@ type Node[ HEAD Head, RPC NodeClient[CHAIN_ID, HEAD], ] interface { - // State returns nodeState + // State returns most accurate state of the Node on the moment of call. + // While some of the checks may be performed in the background and State may return cached value, critical, like + // `FinalizedBlockOutOfSync`, must be executed upon every call. State() nodeState - // StateAndLatest returns nodeState with the latest received block number & total difficulty. - StateAndLatest() (nodeState, int64, *big.Int) + // StateAndLatest returns nodeState with the latest ChainInfo observed by Node during current lifecycle. + StateAndLatest() (nodeState, ChainInfo) + // HighestUserObservations - returns highest ChainInfo ever observed by underlying RPC excluding results of health check requests + HighestUserObservations() ChainInfo + SetPoolChainInfoProvider(PoolChainInfoProvider) // Name is a unique identifier for this node. Name() string String() string RPC() RPC SubscribersCount() int32 + // UnsubscribeAllExceptAliveLoop - closes all subscriptions except the aliveLoop subscription UnsubscribeAllExceptAliveLoop() ConfiguredChainID() CHAIN_ID Order() int32 @@ -96,20 +104,12 @@ type node[ stateMu sync.RWMutex // protects state* fields state nodeState - // Each node is tracking the last received head number and total difficulty - stateLatestBlockNumber int64 - stateLatestTotalDifficulty *big.Int - stateLatestFinalizedBlockNumber int64 + + poolInfoProvider PoolChainInfoProvider stopCh services.StopChan // wg waits for subsidiary goroutines wg sync.WaitGroup - - // nLiveNodes is a passed in function that allows this node to: - // 1. see how many live nodes there are in total, so we can prevent the last alive node in a pool from being - // moved to out-of-sync state. It is better to have one out-of-sync node than no nodes at all. - // 2. compare against the highest head (by number or difficulty) to ensure we don't fall behind too far. - nLiveNodes func() (count int, blockNumber int64, totalDifficulty *big.Int) } func NewNode[ @@ -150,7 +150,6 @@ func NewNode[ "nodeOrder", n.order, ) n.lfcLog = logger.Named(lggr, "Lifecycle") - n.stateLatestBlockNumber = -1 n.rpc = rpc n.chainFamily = chainFamily return n @@ -243,7 +242,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verifyChainID(callerCtx context.Context, lgg promPoolRPCNodeVerifiesFailed.WithLabelValues(n.chainFamily, n.chainID.String(), n.name).Inc() } - st := n.State() + st := n.getCachedState() switch st { case nodeStateClosed: // The node is already closed, and any subsequent transition is invalid. @@ -258,7 +257,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verifyChainID(callerCtx context.Context, lgg var err error if chainID, err = n.rpc.ChainID(callerCtx); err != nil { promFailed() - lggr.Errorw("Failed to verify chain ID for node", "err", err, "nodeState", n.State()) + lggr.Errorw("Failed to verify chain ID for node", "err", err, "nodeState", n.getCachedState()) return nodeStateUnreachable } else if chainID.String() != n.chainID.String() { promFailed() @@ -269,7 +268,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verifyChainID(callerCtx context.Context, lgg n.name, errInvalidChainID, ) - lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err, "nodeState", n.State()) + lggr.Errorw("Failed to verify RPC node; remote endpoint returned the wrong chain ID", "err", err, "nodeState", n.getCachedState()) return nodeStateInvalidChainID } @@ -282,7 +281,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verifyChainID(callerCtx context.Context, lgg // 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()) + n.lfcLog.Errorw("Dial failed: Node is unreachable", "err", err, "nodeState", n.getCachedState()) return nodeStateUnreachable } @@ -300,12 +299,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verifyConn(ctx context.Context, lggr logger. 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()) + lggr.Errorw("Unexpected error while verifying RPC node synchronization status", "err", err, "nodeState", n.getCachedState()) return nodeStateUnreachable } if isSyncing { - lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.State()) + lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.getCachedState()) return nodeStateSyncing } } @@ -323,3 +322,9 @@ func (n *node[CHAIN_ID, HEAD, RPC]) disconnectAll() { func (n *node[CHAIN_ID, HEAD, RPC]) Order() int32 { return n.order } + +func (n *node[CHAIN_ID, HEAD, RPC]) newCtx() (context.Context, context.CancelFunc) { + ctx, cancel := n.stopCh.NewCtx() + ctx = CtxAddHealthCheckFlag(ctx) + return ctx, cancel +} diff --git a/common/client/node_fsm.go b/common/client/node_fsm.go index e9105dcc060..5a5e2554431 100644 --- a/common/client/node_fsm.go +++ b/common/client/node_fsm.go @@ -63,6 +63,8 @@ func (n nodeState) String() string { return "Closed" case nodeStateSyncing: return "Syncing" + case nodeStateFinalizedBlockOutOfSync: + return "FinalizedBlockOutOfSync" default: return fmt.Sprintf("nodeState(%d)", n) } @@ -98,6 +100,8 @@ const ( // to other primary nodes configured in the MultiNode. In contrast, `nodeStateSyncing` represents the internal state of // the node (RPC). nodeStateSyncing + // nodeStateFinalizedBlockOutOfSync - node is lagging behind on latest finalized block + nodeStateFinalizedBlockOutOfSync // nodeStateLen tracks the number of states nodeStateLen ) @@ -115,15 +119,59 @@ func init() { // State allows reading the current state of the node. func (n *node[CHAIN_ID, HEAD, RPC]) State() nodeState { + n.stateMu.RLock() + defer n.stateMu.RUnlock() + return n.recalculateState() +} + +func (n *node[CHAIN_ID, HEAD, RPC]) getCachedState() nodeState { n.stateMu.RLock() defer n.stateMu.RUnlock() return n.state } -func (n *node[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { +func (n *node[CHAIN_ID, HEAD, RPC]) recalculateState() nodeState { + if n.state != nodeStateAlive { + return n.state + } + + // double check that node is not lagging on finalized block + if n.nodePoolCfg.EnforceRepeatableRead() && n.isFinalizedBlockOutOfSync() { + return nodeStateFinalizedBlockOutOfSync + } + + return nodeStateAlive +} + +func (n *node[CHAIN_ID, HEAD, RPC]) isFinalizedBlockOutOfSync() bool { + if n.poolInfoProvider == nil { + return false + } + + highestObservedByCaller := n.poolInfoProvider.HighestUserObservations() + latest, _ := n.rpc.GetInterceptedChainInfo() + if n.chainCfg.FinalityTagEnabled() { + return latest.FinalizedBlockNumber < highestObservedByCaller.FinalizedBlockNumber-int64(n.chainCfg.FinalizedBlockOffset()) + } + + return latest.BlockNumber < highestObservedByCaller.BlockNumber-int64(n.chainCfg.FinalizedBlockOffset()) +} + +// StateAndLatest returns nodeState with the latest ChainInfo observed by Node during current lifecycle. +func (n *node[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, ChainInfo) { n.stateMu.RLock() defer n.stateMu.RUnlock() - return n.state, n.stateLatestBlockNumber, n.stateLatestTotalDifficulty + latest, _ := n.rpc.GetInterceptedChainInfo() + return n.recalculateState(), latest +} + +// HighestUserObservations - returns highest ChainInfo ever observed by external user of the Node +func (n *node[CHAIN_ID, HEAD, RPC]) HighestUserObservations() ChainInfo { + _, highestUserObservations := n.rpc.GetInterceptedChainInfo() + return highestUserObservations +} +func (n *node[CHAIN_ID, HEAD, RPC]) SetPoolChainInfoProvider(poolInfoProvider PoolChainInfoProvider) { + n.poolInfoProvider = poolInfoProvider } // setState is only used by internal state management methods. @@ -243,7 +291,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToUnreachable(fn func()) { } func (n *node[CHAIN_ID, HEAD, RPC]) declareState(state nodeState) { - if n.State() == nodeStateClosed { + if n.getCachedState() == nodeStateClosed { return } switch state { diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 5947774e202..39e17bb4972 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -56,20 +56,11 @@ func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { return utils.WithJitter(interval) } -func (n *node[CHAIN_ID, HEAD, RPC]) setLatestReceived(blockNumber int64, totalDifficulty *big.Int) { - n.stateMu.Lock() - defer n.stateMu.Unlock() - n.stateLatestBlockNumber = blockNumber - n.stateLatestTotalDifficulty = totalDifficulty -} - const ( msgCannotDisable = "but cannot disable this connection because there are no other RPC endpoints, or all other RPC endpoints are dead." msgDegradedState = "Chainlink is now operating in a degraded state and urgent action is required to resolve the issue" ) -const rpcSubscriptionMethodNewHeads = "newHeads" - // Node is a FSM // Each state has a loop that goes with it, which monitors the node and moves it into another state as necessary. // Only one loop must run at a time. @@ -79,12 +70,12 @@ const rpcSubscriptionMethodNewHeads = "newHeads" // Should only be run ONCE per node, after a successful Dial func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { defer n.wg.Done() - ctx, cancel := n.stopCh.NewCtx() + ctx, cancel := n.newCtx() defer cancel() { // sanity check - state := n.State() + state := n.getCachedState() switch state { case nodeStateAlive: case nodeStateClosed: @@ -99,12 +90,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { pollInterval := n.nodePoolCfg.PollInterval() lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - lggr.Tracew("Alive loop starting", "nodeState", n.State()) + lggr.Tracew("Alive loop starting", "nodeState", n.getCachedState()) headsC := make(chan HEAD) - sub, err := n.rpc.Subscribe(ctx, headsC, rpcSubscriptionMethodNewHeads) + sub, err := n.rpc.SubscribeNewHead(ctx, headsC) if err != nil { - lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.State()) + lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.getCachedState()) n.declareUnreachable() return } @@ -116,7 +107,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { var outOfSyncT *time.Ticker var outOfSyncTC <-chan time.Time if noNewHeadsTimeoutThreshold > 0 { - lggr.Debugw("Head liveness checking enabled", "nodeState", n.State()) + lggr.Debugw("Head liveness checking enabled", "nodeState", n.getCachedState()) outOfSyncT = time.NewTicker(noNewHeadsTimeoutThreshold) defer outOfSyncT.Stop() outOfSyncTC = outOfSyncT.C @@ -148,7 +139,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { pollFinalizedHeadCh = pollT.C } - _, highestReceivedBlockNumber, _ := n.StateAndLatest() + localHighestChainInfo, _ := n.rpc.GetInterceptedChainInfo() var pollFailures uint32 for { @@ -157,7 +148,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { return case <-pollCh: promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + lggr.Tracew("Polling for version", "nodeState", n.getCachedState(), "pollFailures", pollFailures) version, err := func(ctx context.Context) (string, error) { ctx, cancel := context.WithTimeout(ctx, pollInterval) defer cancel() @@ -169,16 +160,16 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { promPoolRPCNodePollsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() pollFailures++ } - lggr.Warnw(fmt.Sprintf("Poll failure, RPC endpoint %s failed to respond properly", n.String()), "err", err, "pollFailures", pollFailures, "nodeState", n.State()) + lggr.Warnw(fmt.Sprintf("Poll failure, RPC endpoint %s failed to respond properly", n.String()), "err", err, "pollFailures", pollFailures, "nodeState", n.getCachedState()) } else { - lggr.Debugw("Version poll successful", "nodeState", n.State(), "clientVersion", version) + lggr.Debugw("Version poll successful", "nodeState", n.getCachedState(), "clientVersion", version) promPoolRPCNodePollsSuccess.WithLabelValues(n.chainID.String(), n.name).Inc() pollFailures = 0 } if pollFailureThreshold > 0 && pollFailures >= pollFailureThreshold { - lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) - if n.nLiveNodes != nil { - if l, _, _ := n.nLiveNodes(); l < 2 { + lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.getCachedState()) + if n.poolInfoProvider != nil { + if l, _ := n.poolInfoProvider.LatestChainInfo(); l < 2 { lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } @@ -186,10 +177,10 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { n.declareUnreachable() return } - _, num, td := n.StateAndLatest() - if outOfSync, liveNodes := n.syncStatus(num, td); outOfSync { + _, ci := n.StateAndLatest() + if outOfSync, liveNodes := n.syncStatus(ci.BlockNumber, ci.TotalDifficulty); outOfSync { // note: there must be another live node for us to be out of sync - lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) + lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", ci.BlockNumber, "totalDifficulty", ci.TotalDifficulty, "nodeState", n.getCachedState()) if liveNodes < 2 { lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue @@ -199,40 +190,39 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { } case bh, open := <-headsC: if !open { - lggr.Errorw("Subscription channel unexpectedly closed", "nodeState", n.State()) + lggr.Errorw("Subscription channel unexpectedly closed", "nodeState", n.getCachedState()) n.declareUnreachable() return } promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() lggr.Tracew("Got head", "head", bh) - if bh.BlockNumber() > highestReceivedBlockNumber { + if bh.BlockNumber() > localHighestChainInfo.BlockNumber { promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber())) - lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) - highestReceivedBlockNumber = bh.BlockNumber() + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.getCachedState()) + localHighestChainInfo.BlockNumber = bh.BlockNumber() } else { - lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.getCachedState()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) } - n.setLatestReceived(bh.BlockNumber(), bh.BlockDifficulty()) if !n.chainCfg.FinalityTagEnabled() { latestFinalizedBN := max(bh.BlockNumber()-int64(n.chainCfg.FinalityDepth()), 0) - if latestFinalizedBN > n.stateLatestFinalizedBlockNumber { + if latestFinalizedBN > localHighestChainInfo.FinalizedBlockNumber { promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN)) - n.stateLatestFinalizedBlockNumber = latestFinalizedBN + localHighestChainInfo.FinalizedBlockNumber = latestFinalizedBN } } case err := <-sub.Err(): - lggr.Errorw("Subscription was terminated", "err", err, "nodeState", n.State()) + lggr.Errorw("Subscription was terminated", "err", err, "nodeState", n.getCachedState()) n.declareUnreachable() return case <-outOfSyncTC: // We haven't received a head on the channel for at least the // threshold amount of time, mark it broken - lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) - if n.nLiveNodes != nil { - if l, _, _ := n.nLiveNodes(); l < 2 { + lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, localHighestChainInfo.BlockNumber), "nodeState", n.getCachedState(), "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) + if n.poolInfoProvider != nil { + if l, _ := n.poolInfoProvider.LatestChainInfo(); l < 2 { lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state @@ -240,7 +230,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { continue } } - n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < highestReceivedBlockNumber }) + n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < localHighestChainInfo.BlockNumber }) return case <-pollFinalizedHeadCh: latestFinalized, err := func(ctx context.Context) (HEAD, error) { @@ -259,9 +249,9 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { } latestFinalizedBN := latestFinalized.BlockNumber() - if latestFinalizedBN > n.stateLatestFinalizedBlockNumber { + if latestFinalizedBN > localHighestChainInfo.FinalizedBlockNumber { promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN)) - n.stateLatestFinalizedBlockNumber = latestFinalizedBN + localHighestChainInfo.FinalizedBlockNumber = latestFinalizedBN } } } @@ -276,7 +266,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *big.Int) (outOfSy // Always returns outOfSync false for SyncThreshold 0. // liveNodes is only included when outOfSync is true. func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *big.Int) (outOfSync bool, liveNodes int) { - if n.nLiveNodes == nil { + if n.poolInfoProvider == nil { return // skip for tests } threshold := n.nodePoolCfg.SyncThreshold() @@ -284,14 +274,14 @@ func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *big.Int) (outOfSyn return // disabled } // Check against best node - ln, highest, greatest := n.nLiveNodes() + ln, ci := n.poolInfoProvider.LatestChainInfo() mode := n.nodePoolCfg.SelectionMode() switch mode { case NodeSelectionModeHighestHead, NodeSelectionModeRoundRobin, NodeSelectionModePriorityLevel: - return num < highest-int64(threshold), ln + return num < ci.BlockNumber-int64(threshold), ln case NodeSelectionModeTotalDifficulty: bigThreshold := big.NewInt(int64(threshold)) - return td.Cmp(bigmath.Sub(greatest, bigThreshold)) < 0, ln + return td.Cmp(bigmath.Sub(ci.TotalDifficulty, bigThreshold)) < 0, ln default: panic("unrecognized NodeSelectionMode: " + mode) } @@ -305,12 +295,12 @@ const ( // outOfSyncLoop takes an OutOfSync node and waits until isOutOfSync returns false to go back to live status func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { defer n.wg.Done() - ctx, cancel := n.stopCh.NewCtx() + ctx, cancel := n.newCtx() defer cancel() { // sanity check - state := n.State() + state := n.getCachedState() switch state { case nodeStateOutOfSync: case nodeStateClosed: @@ -323,7 +313,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td outOfSyncAt := time.Now() lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync")) - lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) + lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.getCachedState()) // Need to redial since out-of-sync nodes are automatically disconnected state := n.createVerifiedConn(ctx, lggr) @@ -332,12 +322,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return } - lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.getCachedState()) ch := make(chan HEAD) - sub, err := n.rpc.Subscribe(ctx, ch, rpcSubscriptionMethodNewHeads) + sub, err := n.rpc.SubscribeNewHead(ctx, ch) if err != nil { - lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "nodeState", n.State(), "err", err) + lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "nodeState", n.getCachedState(), "err", err) n.declareUnreachable() return } @@ -349,28 +339,27 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return case head, open := <-ch: if !open { - lggr.Error("Subscription channel unexpectedly closed", "nodeState", n.State()) + lggr.Error("Subscription channel unexpectedly closed", "nodeState", n.getCachedState()) n.declareUnreachable() return } - n.setLatestReceived(head.BlockNumber(), head.BlockDifficulty()) if !isOutOfSync(head.BlockNumber(), head.BlockDifficulty()) { // back in-sync! flip back into alive loop - lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)), "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.State()) + lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)), "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.getCachedState()) n.declareInSync() return } - lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.State()) + lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.getCachedState()) case <-time.After(zombieNodeCheckInterval(n.chainCfg.NodeNoNewHeadsThreshold())): - if n.nLiveNodes != nil { - if l, _, _ := n.nLiveNodes(); l < 1 { + if n.poolInfoProvider != nil { + if l, _ := n.poolInfoProvider.LatestChainInfo(); l < 1 { lggr.Critical("RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") n.declareInSync() return } } case err := <-sub.Err(): - lggr.Errorw("Subscription was terminated", "nodeState", n.State(), "err", err) + lggr.Errorw("Subscription was terminated", "nodeState", n.getCachedState(), "err", err) n.declareUnreachable() return } @@ -379,12 +368,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { defer n.wg.Done() - ctx, cancel := n.stopCh.NewCtx() + ctx, cancel := n.newCtx() defer cancel() { // sanity check - state := n.State() + state := n.getCachedState() switch state { case nodeStateUnreachable: case nodeStateClosed: @@ -397,7 +386,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { unreachableAt := time.Now() lggr := logger.Sugared(logger.Named(n.lfcLog, "Unreachable")) - lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) + lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.getCachedState()) dialRetryBackoff := iutils.NewRedialBackoff() @@ -406,11 +395,11 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { case <-ctx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.getCachedState()) err := n.rpc.Dial(ctx) if err != nil { - lggr.Errorw(fmt.Sprintf("Failed to redial RPC node; still unreachable: %v", err), "err", err, "nodeState", n.State()) + lggr.Errorw(fmt.Sprintf("Failed to redial RPC node; still unreachable: %v", err), "err", err, "nodeState", n.getCachedState()) continue } @@ -422,7 +411,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { 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()) + lggr.Infow(fmt.Sprintf("Successfully redialled and verified RPC node %s. Node was offline for %s", n.String(), time.Since(unreachableAt)), "nodeState", n.getCachedState()) fallthrough default: n.declareState(state) @@ -434,12 +423,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { defer n.wg.Done() - ctx, cancel := n.stopCh.NewCtx() + ctx, cancel := n.newCtx() defer cancel() { // sanity check - state := n.State() + state := n.getCachedState() switch state { case nodeStateInvalidChainID: case nodeStateClosed: @@ -460,7 +449,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { return } - lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) + lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.getCachedState()) chainIDRecheckBackoff := iutils.NewRedialBackoff() @@ -474,7 +463,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { case nodeStateInvalidChainID: continue case nodeStateAlive: - lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was offline for %s", time.Since(invalidAt)), "nodeState", n.State()) + lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was offline for %s", time.Since(invalidAt)), "nodeState", n.getCachedState()) fallthrough default: n.declareState(state) @@ -486,12 +475,12 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { func (n *node[CHAIN_ID, HEAD, RPC]) syncingLoop() { defer n.wg.Done() - ctx, cancel := n.stopCh.NewCtx() + ctx, cancel := n.newCtx() defer cancel() { // sanity check - state := n.State() + state := n.getCachedState() switch state { case nodeStateSyncing: case nodeStateClosed: @@ -504,7 +493,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) syncingLoop() { 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()) + lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with syncing status", n.String()), "nodeState", n.getCachedState()) // Need to redial since syncing nodes are automatically disconnected state := n.createVerifiedConn(ctx, lggr) if state != nodeStateSyncing { @@ -519,20 +508,20 @@ func (n *node[CHAIN_ID, HEAD, RPC]) syncingLoop() { case <-ctx.Done(): return case <-time.After(recheckBackoff.Duration()): - lggr.Tracew("Trying to recheck if the node is still syncing", "nodeState", n.State()) + lggr.Tracew("Trying to recheck if the node is still syncing", "nodeState", n.getCachedState()) isSyncing, err := n.rpc.IsSyncing(ctx) if err != nil { - lggr.Errorw("Unexpected error while verifying RPC node synchronization status", "err", err, "nodeState", n.State()) + lggr.Errorw("Unexpected error while verifying RPC node synchronization status", "err", err, "nodeState", n.getCachedState()) n.declareUnreachable() return } if isSyncing { - lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.State()) + lggr.Errorw("Verification failed: Node is syncing", "nodeState", n.getCachedState()) continue } - lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was syncing for %s", time.Since(syncingAt)), "nodeState", n.State()) + lggr.Infow(fmt.Sprintf("Successfully verified RPC node. Node was syncing for %s", time.Since(syncingAt)), "nodeState", n.getCachedState()) n.declareAlive() return } diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 4bdfd698f7a..863a15a1fad 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -15,7 +15,6 @@ import ( "go.uber.org/zap" "github.com/smartcontractkit/chainlink-common/pkg/logger" - bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" clientMocks "github.com/smartcontractkit/chainlink/v2/common/client/mocks" @@ -49,8 +48,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { defer func() { assert.NoError(t, node.close()) }() expectedError := errors.New("failed to subscribe to rpc") - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(nil, expectedError).Once() rpc.On("DisconnectAll").Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(nil, expectedError).Once() // might be called in unreachable loop rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() node.declareAlive() @@ -67,6 +66,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { rpc: rpc, lggr: lggr, }) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() defer func() { assert.NoError(t, node.close()) }() sub := mocks.NewSubscription(t) @@ -74,7 +74,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { close(errChan) sub.On("Err").Return((<-chan error)(errChan)).Once() sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once() rpc.On("SetAliveLoopSub", sub).Once() // disconnects all on transfer to unreachable rpc.On("DisconnectAll").Once() @@ -89,13 +89,14 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - opts.rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + opts.rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once() opts.rpc.On("SetAliveLoopSub", sub).Once() return newDialedNode(t, opts) } t.Run("Stays alive and waits for signal", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{}, @@ -111,6 +112,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Run("stays alive while below pollFailureThreshold and resets counter on success", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}) lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const pollFailureThreshold = 3 node := newSubscribedNode(t, testNodeOpts{ @@ -152,6 +154,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Run("with threshold poll failures, transitions to unreachable", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}) lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) const pollFailureThreshold = 3 node := newSubscribedNode(t, testNodeOpts{ @@ -189,9 +192,12 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 1, 20, big.NewInt(10) - } + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(1, ChainInfo{ + BlockNumber: 20, + }).Once() + node.SetPoolChainInfoProvider(poolInfo) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: 20}, ChainInfo{BlockNumber: 20}) pollError := errors.New("failed to get ClientVersion") rpc.On("ClientVersion", mock.Anything).Return("", pollError) node.declareAlive() @@ -213,10 +219,14 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() - node.stateLatestBlockNumber = 20 - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 10, syncThreshold + node.stateLatestBlockNumber + 1, big.NewInt(10) - } + const mostRecentBlock = 20 + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: mostRecentBlock}, ChainInfo{BlockNumber: 30}) + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(10, ChainInfo{ + BlockNumber: syncThreshold + mostRecentBlock + 1, + TotalDifficulty: big.NewInt(10), + }).Once() + node.SetPoolChainInfoProvider(poolInfo) rpc.On("ClientVersion", mock.Anything).Return("", nil) // tries to redial in outOfSync rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Run(func(_ mock.Arguments) { @@ -246,10 +256,14 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() - node.stateLatestBlockNumber = 20 - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 1, syncThreshold + node.stateLatestBlockNumber + 1, big.NewInt(10) - } + const mostRecentBlock = 20 + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: mostRecentBlock}, ChainInfo{BlockNumber: 30}) + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(1, ChainInfo{ + BlockNumber: syncThreshold + mostRecentBlock + 1, + TotalDifficulty: big.NewInt(10), + }).Once() + node.SetPoolChainInfoProvider(poolInfo) rpc.On("ClientVersion", mock.Anything).Return("", nil) node.declareAlive() tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState)) @@ -268,19 +282,17 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() - node.stateLatestBlockNumber = 20 - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 1, node.stateLatestBlockNumber + 100, big.NewInt(10) - } + const mostRecentBlock = 20 + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: mostRecentBlock}, ChainInfo{BlockNumber: 30}) rpc.On("ClientVersion", mock.Anything).Return("", nil) node.declareAlive() tests.AssertLogCountEventually(t, observedLogs, "Version poll successful", 2) assert.Equal(t, nodeStateAlive, node.State()) }) - t.Run("when no new heads received for threshold, transitions to out of sync", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{}, chainConfig: clientMocks.ChainConfig{ @@ -307,6 +319,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Run("when no new heads received for threshold but we are the last live node, forcibly stays alive", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ config: testNodeConfig{}, @@ -317,21 +330,24 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { rpc: rpc, }) defer func() { assert.NoError(t, node.close()) }() - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 1, 20, big.NewInt(10) - } + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(1, ChainInfo{ + BlockNumber: 20, + TotalDifficulty: big.NewInt(10), + }).Once() + node.SetPoolChainInfoProvider(poolInfo) node.declareAlive() tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState)) assert.Equal(t, nodeStateAlive, node.State()) }) - t.Run("rpc closed head channel", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) close(ch) }).Return(sub, nil).Once() @@ -354,30 +370,6 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { tests.AssertLogEventually(t, observedLogs, "Subscription channel unexpectedly closed") assert.Equal(t, nodeStateUnreachable, node.State()) }) - t.Run("updates block number and difficulty on new head", func(t *testing.T) { - t.Parallel() - rpc := newMockNodeClient[types.ID, Head](t) - sub := mocks.NewSubscription(t) - sub.On("Err").Return((<-chan error)(nil)) - sub.On("Unsubscribe").Once() - expectedBlockNumber := rand.Int64() - expectedDiff := big.NewInt(rand.Int64()) - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { - ch := args.Get(1).(chan<- Head) - go writeHeads(t, ch, head{BlockNumber: expectedBlockNumber, BlockDifficulty: expectedDiff}) - }).Return(sub, nil).Once() - rpc.On("SetAliveLoopSub", sub).Once() - node := newDialedNode(t, testNodeOpts{ - config: testNodeConfig{}, - rpc: rpc, - }) - defer func() { assert.NoError(t, node.close()) }() - node.declareAlive() - tests.AssertEventually(t, func() bool { - state, block, diff := node.StateAndLatest() - return state == nodeStateAlive && block == expectedBlockNumber == bigmath.Equal(diff, expectedDiff) - }) - }) t.Run("If finality tag is not enabled updates finalized block metric using finality depth and latest head", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) @@ -387,7 +379,8 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { const blockNumber = 1000 const finalityDepth = 10 const expectedBlock = 990 - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) go writeHeads(t, ch, head{BlockNumber: blockNumber - 1}, head{BlockNumber: blockNumber}, head{BlockNumber: blockNumber - 1}) }).Return(sub, nil).Once() @@ -413,11 +406,12 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Run("Logs warning if failed to get finalized block", func(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() rpc.On("LatestFinalizedBlock", mock.Anything).Return(newMockHead(t), errors.New("failed to get finalized block")) sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once() rpc.On("SetAliveLoopSub", sub).Once() lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newDialedNode(t, testNodeOpts{ @@ -440,10 +434,11 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { head := newMockHead(t) head.On("IsValid").Return(false) rpc.On("LatestFinalizedBlock", mock.Anything).Return(head, nil) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once() rpc.On("SetAliveLoopSub", sub).Once() lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newDialedNode(t, testNodeOpts{ @@ -470,12 +465,13 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) // ensure that "calculated" finalized head is larger than actual, to ensure we are correctly setting // the metric go writeHeads(t, ch, head{BlockNumber: expectedBlock*2 + finalityDepth}) }).Return(sub, nil).Once() + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once() rpc.On("SetAliveLoopSub", sub).Once() name := "node-" + rand.Str(5) node := newDialedNode(t, testNodeOpts{ @@ -531,8 +527,9 @@ func setupRPCForAliveLoop(t *testing.T, rpc *mockNodeClient[types.ID, Head]) { aliveSubscription := mocks.NewSubscription(t) aliveSubscription.On("Err").Return((<-chan error)(nil)).Maybe() aliveSubscription.On("Unsubscribe").Maybe() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(aliveSubscription, nil).Maybe() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(aliveSubscription, nil).Maybe() rpc.On("SetAliveLoopSub", mock.Anything).Maybe() + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Maybe() } func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { @@ -577,7 +574,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) outOfSyncSubscription.On("Unsubscribe").Once() heads := []head{{BlockNumber: 7}, {BlockNumber: 11}, {BlockNumber: 13}} - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) go writeHeads(t, ch, heads...) }).Return(outOfSyncSubscription, nil).Once() @@ -701,7 +698,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { rpc.On("Dial", mock.Anything).Return(nil).Once() 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) + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(nil, expectedError) rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() node.declareOutOfSync(stubIsOutOfSync) tests.AssertEventually(t, func() bool { @@ -728,7 +725,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { errChan <- errors.New("subscription was terminate") sub.On("Err").Return((<-chan error)(errChan)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once() rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() node.declareOutOfSync(stubIsOutOfSync) tests.AssertLogEventually(t, observedLogs, "Subscription was terminated") @@ -754,7 +751,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { sub := mocks.NewSubscription(t) sub.On("Err").Return((<-chan error)(nil)) sub.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) close(ch) }).Return(sub, nil).Once() @@ -785,10 +782,11 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) outOfSyncSubscription.On("Unsubscribe").Once() const highestBlock = 1000 - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { ch := args.Get(1).(chan<- Head) go writeHeads(t, ch, head{BlockNumber: highestBlock - 1}, head{BlockNumber: highestBlock}) }).Return(outOfSyncSubscription, nil).Once() + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: highestBlock}, ChainInfo{BlockNumber: highestBlock}) setupRPCForAliveLoop(t, rpc) @@ -815,9 +813,13 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return 0, 100, big.NewInt(200) - } + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(0, ChainInfo{ + BlockNumber: 100, + TotalDifficulty: big.NewInt(200), + }) + node.SetPoolChainInfoProvider(poolInfo) + rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: 0}, ChainInfo{BlockNumber: 0}) rpc.On("Dial", mock.Anything).Return(nil).Once() rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() @@ -825,7 +827,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { outOfSyncSubscription := mocks.NewSubscription(t) outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) outOfSyncSubscription.On("Unsubscribe").Once() - rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(outOfSyncSubscription, nil).Once() + rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(outOfSyncSubscription, nil).Once() setupRPCForAliveLoop(t, rpc) @@ -1304,9 +1306,8 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { }) t.Run("skip if syncThreshold is not configured", func(t *testing.T) { node := newTestNode(t, testNodeOpts{}) - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return - } + poolInfo := newMockPoolChainInfoProvider(t) + node.SetPoolChainInfoProvider(poolInfo) outOfSync, liveNodes := node.syncStatus(0, nil) assert.Equal(t, false, outOfSync) assert.Equal(t, 0, liveNodes) @@ -1315,9 +1316,9 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { node := newTestNode(t, testNodeOpts{ config: testNodeConfig{syncThreshold: 1}, }) - node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { - return - } + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(1, ChainInfo{}).Once() + node.SetPoolChainInfoProvider(poolInfo) assert.Panics(t, func() { _, _ = node.syncStatus(0, nil) }) @@ -1361,9 +1362,12 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { selectionMode: selectionMode, }, }) - node.nLiveNodes = func() (int, int64, *big.Int) { - return nodesNum, highestBlock, big.NewInt(totalDifficulty) - } + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(nodesNum, ChainInfo{ + BlockNumber: highestBlock, + TotalDifficulty: big.NewInt(totalDifficulty), + }) + node.SetPoolChainInfoProvider(poolInfo) for _, td := range []int64{totalDifficulty - syncThreshold - 1, totalDifficulty - syncThreshold, totalDifficulty, totalDifficulty + 1} { for _, testCase := range testCases { t.Run(fmt.Sprintf("%s: SelectionModeVal: %s: total difficulty: %d", testCase.name, selectionMode, td), func(t *testing.T) { @@ -1413,9 +1417,13 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { selectionMode: NodeSelectionModeTotalDifficulty, }, }) - node.nLiveNodes = func() (int, int64, *big.Int) { - return nodesNum, highestBlock, big.NewInt(totalDifficulty) - } + + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("LatestChainInfo").Return(nodesNum, ChainInfo{ + BlockNumber: highestBlock, + TotalDifficulty: big.NewInt(totalDifficulty), + }) + node.SetPoolChainInfoProvider(poolInfo) for _, hb := range []int64{highestBlock - syncThreshold - 1, highestBlock - syncThreshold, highestBlock, highestBlock + 1} { for _, testCase := range testCases { t.Run(fmt.Sprintf("%s: SelectionModeVal: %s: highest block: %d", testCase.name, NodeSelectionModeTotalDifficulty, hb), func(t *testing.T) { @@ -1573,3 +1581,98 @@ func TestUnit_NodeLifecycle_SyncingLoop(t *testing.T) { }) }) } + +func TestNode_State(t *testing.T) { + t.Run("If not Alive, returns as is", func(t *testing.T) { + for state := nodeState(0); state < nodeStateLen; state++ { + if state == nodeStateAlive { + continue + } + + node := newTestNode(t, testNodeOpts{}) + node.setState(state) + assert.Equal(t, state, node.State()) + } + }) + t.Run("If repeatable read is not enforced, returns alive", func(t *testing.T) { + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateAlive) + assert.Equal(t, nodeStateAlive, node.State()) + }) + testCases := []struct { + Name string + FinalizedBlockOffsetVal uint32 + IsFinalityTagEnabled bool + PoolChainInfo ChainInfo + NodeChainInfo ChainInfo + ExpectedState nodeState + }{ + { + Name: "If finality lag does not exceeds offset, returns alive (FinalityDepth)", + FinalizedBlockOffsetVal: 15, + PoolChainInfo: ChainInfo{ + BlockNumber: 20, + }, + NodeChainInfo: ChainInfo{ + BlockNumber: 5, + }, + ExpectedState: nodeStateAlive, + }, + { + Name: "If finality lag does not exceeds offset, returns alive (FinalityTag)", + FinalizedBlockOffsetVal: 15, + IsFinalityTagEnabled: true, + PoolChainInfo: ChainInfo{ + FinalizedBlockNumber: 20, + }, + NodeChainInfo: ChainInfo{ + FinalizedBlockNumber: 5, + }, + ExpectedState: nodeStateAlive, + }, + { + Name: "If finality lag exceeds offset, returns nodeStateFinalizedBlockOutOfSync (FinalityDepth)", + FinalizedBlockOffsetVal: 15, + PoolChainInfo: ChainInfo{ + BlockNumber: 20, + }, + NodeChainInfo: ChainInfo{ + BlockNumber: 4, + }, + ExpectedState: nodeStateFinalizedBlockOutOfSync, + }, + { + Name: "If finality lag exceeds offset, returns nodeStateFinalizedBlockOutOfSync (FinalityTag)", + FinalizedBlockOffsetVal: 15, + IsFinalityTagEnabled: true, + PoolChainInfo: ChainInfo{ + FinalizedBlockNumber: 20, + }, + NodeChainInfo: ChainInfo{ + FinalizedBlockNumber: 4, + }, + ExpectedState: nodeStateFinalizedBlockOutOfSync, + }, + } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("GetInterceptedChainInfo").Return(tc.NodeChainInfo, tc.PoolChainInfo).Once() + node := newTestNode(t, testNodeOpts{ + config: testNodeConfig{ + enforceRepeatableRead: true, + }, + chainConfig: clientMocks.ChainConfig{ + FinalizedBlockOffsetVal: tc.FinalizedBlockOffsetVal, + IsFinalityTagEnabled: tc.IsFinalityTagEnabled, + }, + rpc: rpc, + }) + poolInfo := newMockPoolChainInfoProvider(t) + poolInfo.On("HighestUserObservations").Return(tc.PoolChainInfo).Once() + node.SetPoolChainInfoProvider(poolInfo) + node.setState(nodeStateAlive) + assert.Equal(t, tc.ExpectedState, node.State()) + }) + } +} diff --git a/common/client/node_selector_highest_head.go b/common/client/node_selector_highest_head.go index 99a130004a9..25a931fc01b 100644 --- a/common/client/node_selector_highest_head.go +++ b/common/client/node_selector_highest_head.go @@ -24,7 +24,8 @@ func (s highestHeadNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HE var highestHeadNumber int64 = math.MinInt64 var highestHeadNodes []Node[CHAIN_ID, HEAD, RPC] for _, n := range s { - state, currentHeadNumber, _ := n.StateAndLatest() + state, currentChainInfo := n.StateAndLatest() + currentHeadNumber := currentChainInfo.BlockNumber if state == nodeStateAlive && currentHeadNumber >= highestHeadNumber { if highestHeadNumber < currentHeadNumber { highestHeadNumber = currentHeadNumber diff --git a/common/client/node_selector_highest_head_test.go b/common/client/node_selector_highest_head_test.go index 6e47bbedcae..e245924589c 100644 --- a/common/client/node_selector_highest_head_test.go +++ b/common/client/node_selector_highest_head_test.go @@ -24,13 +24,13 @@ func TestHighestHeadNodeSelector(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) if i == 0 { // first node is out of sync - node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + node.On("StateAndLatest").Return(nodeStateOutOfSync, ChainInfo{BlockNumber: int64(-1)}) } else if i == 1 { // second node is alive, LatestReceivedBlockNumber = 1 - node.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(1)}) } else { // third node is alive, LatestReceivedBlockNumber = 2 (best node) - node.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(2)}) } node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -42,7 +42,7 @@ func TestHighestHeadNodeSelector(t *testing.T) { t.Run("stick to the same node", func(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) // fourth node is alive, LatestReceivedBlockNumber = 2 (same as 3rd) - node.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(2)}) node.On("Order").Return(int32(1)) nodes = append(nodes, node) @@ -53,7 +53,7 @@ func TestHighestHeadNodeSelector(t *testing.T) { t.Run("another best node", func(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) // fifth node is alive, LatestReceivedBlockNumber = 3 (better than 3rd and 4th) - node.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(3)}) node.On("Order").Return(int32(1)) nodes = append(nodes, node) @@ -63,10 +63,10 @@ func TestHighestHeadNodeSelector(t *testing.T) { t.Run("nodes never update latest block number", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(-1)}) node1.On("Order").Return(int32(1)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(-1)}) node2.On("Order").Return(int32(1)) selector := newNodeSelector(NodeSelectionModeHighestHead, []Node[types.ID, Head, nodeClient]{node1, node2}) assert.Same(t, node1, selector.Select()) @@ -83,10 +83,10 @@ func TestHighestHeadNodeSelector_None(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) if i == 0 { // first node is out of sync - node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + node.On("StateAndLatest").Return(nodeStateOutOfSync, ChainInfo{BlockNumber: int64(-1)}) } else { // others are unreachable - node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), nil) + node.On("StateAndLatest").Return(nodeStateUnreachable, ChainInfo{BlockNumber: int64(-1)}) } nodes = append(nodes, node) } @@ -104,7 +104,7 @@ func TestHighestHeadNodeSelectorWithOrder(t *testing.T) { t.Run("same head and order", func(t *testing.T) { for i := 0; i < 3; i++ { node := newMockNode[types.ID, Head, nodeClient](t) - node.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(1)}) node.On("Order").Return(int32(2)) nodes = append(nodes, node) } @@ -115,15 +115,15 @@ func TestHighestHeadNodeSelectorWithOrder(t *testing.T) { t.Run("same head but different order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(3)}) node1.On("Order").Return(int32(3)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(3)}) node2.On("Order").Return(int32(1)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(3)}) node3.On("Order").Return(int32(2)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -134,15 +134,15 @@ func TestHighestHeadNodeSelectorWithOrder(t *testing.T) { t.Run("different head but same order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(1)}) node1.On("Order").Maybe().Return(int32(3)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(2)}) node2.On("Order").Maybe().Return(int32(3)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(3)}) node3.On("Order").Return(int32(3)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -153,19 +153,19 @@ func TestHighestHeadNodeSelectorWithOrder(t *testing.T) { t.Run("different head and different order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(10), nil) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(10)}) node1.On("Order").Maybe().Return(int32(3)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(11), nil) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(11)}) node2.On("Order").Maybe().Return(int32(4)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(11), nil) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(11)}) node3.On("Order").Maybe().Return(int32(3)) node4 := newMockNode[types.ID, Head, nodeClient](t) - node4.On("StateAndLatest").Return(nodeStateAlive, int64(10), nil) + node4.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: int64(10)}) node4.On("Order").Maybe().Return(int32(1)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3, node4} diff --git a/common/client/node_selector_total_difficulty.go b/common/client/node_selector_total_difficulty.go index 35491503bcc..6b45e75528b 100644 --- a/common/client/node_selector_total_difficulty.go +++ b/common/client/node_selector_total_difficulty.go @@ -27,11 +27,12 @@ func (s totalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID var aliveNodes []Node[CHAIN_ID, HEAD, RPC] for _, n := range s { - state, _, currentTD := n.StateAndLatest() + state, currentChainInfo := n.StateAndLatest() if state != nodeStateAlive { continue } + currentTD := currentChainInfo.TotalDifficulty aliveNodes = append(aliveNodes, n) if currentTD != nil && (highestTD == nil || currentTD.Cmp(highestTD) >= 0) { if highestTD == nil || currentTD.Cmp(highestTD) > 0 { diff --git a/common/client/node_selector_total_difficulty_test.go b/common/client/node_selector_total_difficulty_test.go index 5c43cdd8472..0bc214918d7 100644 --- a/common/client/node_selector_total_difficulty_test.go +++ b/common/client/node_selector_total_difficulty_test.go @@ -1,7 +1,7 @@ package client import ( - big "math/big" + "math/big" "testing" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -24,13 +24,13 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) if i == 0 { // first node is out of sync - node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + node.On("StateAndLatest").Return(nodeStateOutOfSync, ChainInfo{BlockNumber: -1}) } else if i == 1 { // second node is alive - node.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(7)) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(7)}) } else { // third node is alive and best - node.On("StateAndLatest").Return(nodeStateAlive, int64(2), big.NewInt(8)) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 2, TotalDifficulty: big.NewInt(8)}) } node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -42,7 +42,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { t.Run("stick to the same node", func(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) // fourth node is alive (same as 3rd) - node.On("StateAndLatest").Return(nodeStateAlive, int64(2), big.NewInt(8)) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 2, TotalDifficulty: big.NewInt(8)}) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -53,7 +53,7 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { t.Run("another best node", func(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) // fifth node is alive (better than 3rd and 4th) - node.On("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(11)) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 3, TotalDifficulty: big.NewInt(11)}) node.On("Order").Maybe().Return(int32(1)) nodes = append(nodes, node) @@ -63,10 +63,10 @@ func TestTotalDifficultyNodeSelector(t *testing.T) { t.Run("nodes never update latest block number", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: -1, TotalDifficulty: nil}) node1.On("Order").Maybe().Return(int32(1)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: -1, TotalDifficulty: nil}) node2.On("Order").Maybe().Return(int32(1)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2} @@ -85,10 +85,10 @@ func TestTotalDifficultyNodeSelector_None(t *testing.T) { node := newMockNode[types.ID, Head, nodeClient](t) if i == 0 { // first node is out of sync - node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + node.On("StateAndLatest").Return(nodeStateOutOfSync, ChainInfo{BlockNumber: -1, TotalDifficulty: nil}) } else { // others are unreachable - node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), big.NewInt(7)) + node.On("StateAndLatest").Return(nodeStateUnreachable, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(7)}) } nodes = append(nodes, node) } @@ -106,7 +106,7 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("same td and order", func(t *testing.T) { for i := 0; i < 3; i++ { node := newMockNode[types.ID, Head, nodeClient](t) - node.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(10)) + node.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(10)}) node.On("Order").Return(int32(2)) nodes = append(nodes, node) } @@ -117,15 +117,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("same td but different order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(10)) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 3, TotalDifficulty: big.NewInt(10)}) node1.On("Order").Return(int32(3)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(10)) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 3, TotalDifficulty: big.NewInt(10)}) node2.On("Order").Return(int32(1)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), big.NewInt(10)) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 3, TotalDifficulty: big.NewInt(10)}) node3.On("Order").Return(int32(2)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -136,15 +136,15 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("different td but same order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(10)) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(10)}) node1.On("Order").Maybe().Return(int32(3)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(11)) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(11)}) node2.On("Order").Maybe().Return(int32(3)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(12)) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(12)}) node3.On("Order").Return(int32(3)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} @@ -155,19 +155,19 @@ func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { t.Run("different head and different order", func(t *testing.T) { node1 := newMockNode[types.ID, Head, nodeClient](t) - node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(100)) + node1.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(100)}) node1.On("Order").Maybe().Return(int32(4)) node2 := newMockNode[types.ID, Head, nodeClient](t) - node2.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(110)) + node2.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(110)}) node2.On("Order").Maybe().Return(int32(5)) node3 := newMockNode[types.ID, Head, nodeClient](t) - node3.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(110)) + node3.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(110)}) node3.On("Order").Maybe().Return(int32(1)) node4 := newMockNode[types.ID, Head, nodeClient](t) - node4.On("StateAndLatest").Return(nodeStateAlive, int64(1), big.NewInt(105)) + node4.On("StateAndLatest").Return(nodeStateAlive, ChainInfo{BlockNumber: 1, TotalDifficulty: big.NewInt(105)}) node4.On("Order").Maybe().Return(int32(2)) nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3, node4} diff --git a/common/client/node_test.go b/common/client/node_test.go index a97f26555a9..3b971e84902 100644 --- a/common/client/node_test.go +++ b/common/client/node_test.go @@ -17,7 +17,9 @@ type testNodeConfig struct { selectionMode string syncThreshold uint32 nodeIsSyncingEnabled bool + enforceRepeatableRead bool finalizedBlockPollInterval time.Duration + deathDeclarationDelay time.Duration } func (n testNodeConfig) PollFailureThreshold() uint32 { @@ -44,6 +46,14 @@ func (n testNodeConfig) FinalizedBlockPollInterval() time.Duration { return n.finalizedBlockPollInterval } +func (n testNodeConfig) EnforceRepeatableRead() bool { + return n.enforceRepeatableRead +} + +func (n testNodeConfig) DeathDeclarationDelay() time.Duration { + return n.deathDeclarationDelay +} + type testNode struct { *node[types.ID, Head, NodeClient[types.ID, Head]] } diff --git a/common/client/types.go b/common/client/types.go index a27e6a50b73..3d548b9deba 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -66,6 +66,7 @@ type NodeClient[ connection[CHAIN_ID, HEAD] DialHTTP() error + // DisconnectAll - cancels all inflight requests, terminates all subscriptions and resets latest ChainInfo. DisconnectAll() Close() ClientVersion(context.Context) (string, error) @@ -74,6 +75,17 @@ type NodeClient[ UnsubscribeAllExceptAliveLoop() IsSyncing(ctx context.Context) (bool, error) LatestFinalizedBlock(ctx context.Context) (HEAD, error) + // GetInterceptedChainInfo - returns latest and highest observed by application layer ChainInfo. + // latest ChainInfo is the most recent value received within a NodeClient's current lifecycle between Dial and DisconnectAll. + // highestUserObservations ChainInfo is the highest ChainInfo observed excluding health checks calls. + // Its values must not be reset. + // The results of corresponding calls, to get the most recent head and the latest finalized head, must be + // intercepted and reflected in ChainInfo before being returned to a caller. Otherwise, MultiNode is not able to + // provide repeatable read guarantee. + // DisconnectAll must reset latest ChainInfo to default value. + // Ensure implementation does not have a race condition when values are reset before request completion and as + // a result latest ChainInfo contains information from the previous cycle. + GetInterceptedChainInfo() (latest, highestUserObservations ChainInfo) } // clientAPI includes all the direct RPC methods required by the generalized common client to implement its own. @@ -145,5 +157,41 @@ type connection[ ] interface { ChainID(ctx context.Context) (CHAIN_ID, error) Dial(ctx context.Context) error - Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) + SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (types.Subscription, error) +} + +// PoolChainInfoProvider - provides aggregation of nodes pool ChainInfo +// +//go:generate mockery --quiet --name PoolChainInfoProvider --structname mockPoolChainInfoProvider --filename "mock_pool_chain_info_provider_test.go" --inpackage --case=underscore +type PoolChainInfoProvider interface { + // LatestChainInfo - returns number of live nodes available in the pool, so we can prevent the last alive node in a pool from being + // moved to out-of-sync state. It is better to have one out-of-sync node than no nodes at all. + // Returns highest latest ChainInfo within the alive nodes. E.g. most recent block number and highest block number + // observed by Node A are 10 and 15; Node B - 12 and 14. This method will return 12. + LatestChainInfo() (int, ChainInfo) + // HighestUserObservations - returns highest ChainInfo ever observed by any user of MultiNode. + HighestUserObservations() ChainInfo +} + +// ChainInfo - defines RPC's or MultiNode's view on the chain +type ChainInfo struct { + BlockNumber int64 + FinalizedBlockNumber int64 + TotalDifficulty *big.Int +} + +func MaxTotalDifficulty(a, b *big.Int) *big.Int { + if a == nil { + if b == nil { + return nil + } + + return big.NewInt(0).Set(b) + } + + if b == nil || a.Cmp(b) >= 0 { + return big.NewInt(0).Set(a) + } + + return big.NewInt(0).Set(b) } diff --git a/common/client/types_test.go b/common/client/types_test.go new file mode 100644 index 00000000000..68d7a3fe78e --- /dev/null +++ b/common/client/types_test.go @@ -0,0 +1,34 @@ +package client + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMaxDifficulty(t *testing.T) { + cases := []struct { + A, B, Result *big.Int + }{ + { + A: nil, B: nil, Result: nil, + }, + { + A: nil, B: big.NewInt(1), Result: big.NewInt(1), + }, + { + A: big.NewInt(1), B: big.NewInt(1), Result: big.NewInt(1), + }, + { + A: big.NewInt(1), B: big.NewInt(2), Result: big.NewInt(2), + }, + } + + for _, test := range cases { + actualResult := MaxTotalDifficulty(test.A, test.B) + assert.Equal(t, test.Result, actualResult, "expected max(%v, %v) to produce %v", test.A, test.B, test.Result) + inverted := MaxTotalDifficulty(test.B, test.A) + assert.Equal(t, actualResult, inverted, "expected max(%v, %v) == max(%v, %v)", test.A, test.B, test.B, test.A) + } +} diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index 15977c4dfe4..25715b35280 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -36,7 +36,7 @@ type headHandler[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] func(ctx c type HeadListener[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { // ListenForNewHeads kicks off the listen loop (not thread safe) // done() must be executed upon leaving ListenForNewHeads() - ListenForNewHeads(handleNewHead headHandler[H, BLOCK_HASH], done func()) + ListenForNewHeads(onSubscribe func(), handleNewHead headHandler[H, BLOCK_HASH], done func()) // ReceivingHeads returns true if the listener is receiving heads (thread safe) ReceivingHeads() bool @@ -88,7 +88,7 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) Name() string { return hl.logger.Name() } -func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead headHandler[HTH, BLOCK_HASH], done func()) { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(onSubscription func(), handleNewHead headHandler[HTH, BLOCK_HASH], done func()) { defer done() defer hl.unsubscribe() @@ -99,6 +99,8 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead if !hl.subscribe(ctx) { break } + + onSubscription() err := hl.receiveHeaders(ctx, handleNewHead) if ctx.Err() != nil { break diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 48c4859a64c..bc5f5274c0c 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -40,8 +40,11 @@ const HeadsBufferSize = 10 type HeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { services.Service // Backfill given a head will fill in any missing heads up to latestFinalized - Backfill(ctx context.Context, headWithChain, latestFinalized H) (err error) + Backfill(ctx context.Context, headWithChain H) (err error) LatestChain() H + // LatestAndFinalizedBlock - returns latest and latest finalized blocks. + // NOTE: Returns latest finalized block as is, ignoring the FinalityTagBypass feature flag. + LatestAndFinalizedBlock(ctx context.Context) (latest, finalized H, err error) } type headTracker[ @@ -114,16 +117,15 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error // anyway when we connect (but we should not rely on this because it is // not specced). If it happens this is fine, and the head will be // ignored as a duplicate. - err := ht.handleInitialHead(ctx) - if err != nil { - if ctx.Err() != nil { - return ctx.Err() + onSubscribe := func() { + err := ht.handleInitialHead(ctx) + if err != nil { + ht.log.Errorw("Error handling initial head", "err", err.Error()) } - ht.log.Errorw("Error handling initial head", "err", err.Error()) } ht.wgDone.Add(3) - go ht.headListener.ListenForNewHeads(ht.handleNewHead, ht.wgDone.Done) + go ht.headListener.ListenForNewHeads(onSubscribe, ht.handleNewHead, ht.wgDone.Done) go ht.backfillLoop() go ht.broadcastLoop() @@ -145,7 +147,7 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Con } ht.log.Debugw("Got initial head", "head", initialHead, "blockNumber", initialHead.BlockNumber(), "blockHash", initialHead.BlockHash()) - latestFinalized, err := ht.calculateLatestFinalized(ctx, initialHead) + latestFinalized, err := ht.calculateLatestFinalized(ctx, initialHead, ht.htConfig.FinalityTagBypass()) if err != nil { return fmt.Errorf("failed to calculate latest finalized head: %w", err) } @@ -195,7 +197,12 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { return report } -func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain, latestFinalized HTH) (err error) { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain HTH) (err error) { + latestFinalized, err := ht.calculateLatestFinalized(ctx, headWithChain, ht.htConfig.FinalityTagBypass()) + if err != nil { + return fmt.Errorf("failed to calculate finalized block: %w", err) + } + if !latestFinalized.IsValid() { return errors.New("can not perform backfill without a valid latestFinalized head") } @@ -208,6 +215,11 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, hea return errors.New(errMsg) } + if headWithChain.BlockNumber()-latestFinalized.BlockNumber() > int64(ht.htConfig.MaxAllowedFinalityDepth()) { + return fmt.Errorf("gap between latest finalized block (%d) and current head (%d) is too large (> %d)", + latestFinalized.BlockNumber(), headWithChain.BlockNumber(), ht.htConfig.MaxAllowedFinalityDepth()) + } + return ht.backfill(ctx, headWithChain, latestFinalized) } @@ -317,13 +329,7 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() { break } { - latestFinalized, err := ht.calculateLatestFinalized(ctx, head) - if err != nil { - ht.log.Warnw("Failed to calculate finalized block", "err", err) - continue - } - - err = ht.Backfill(ctx, head, latestFinalized) + err := ht.Backfill(ctx, head) if err != nil { ht.log.Warnw("Unexpected error while backfilling heads", "err", err) } else if ctx.Err() != nil { @@ -335,12 +341,58 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() { } } +// LatestAndFinalizedBlock - returns latest and latest finalized blocks. +// NOTE: Returns latest finalized block as is, ignoring the FinalityTagBypass feature flag. +// TODO: BCI-3321 use cached values instead of making RPC requests +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) LatestAndFinalizedBlock(ctx context.Context) (latest, finalized HTH, err error) { + latest, err = ht.client.HeadByNumber(ctx, nil) + if err != nil { + err = fmt.Errorf("failed to get latest block: %w", err) + return + } + + if !latest.IsValid() { + err = fmt.Errorf("expected latest block to be valid") + return + } + + finalized, err = ht.calculateLatestFinalized(ctx, latest, false) + if err != nil { + err = fmt.Errorf("failed to calculate latest finalized block: %w", err) + return + } + if !finalized.IsValid() { + err = fmt.Errorf("expected finalized block to be valid") + return + } + + return +} + +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) getHeadAtHeight(ctx context.Context, chainHeadHash BLOCK_HASH, blockHeight int64) (HTH, error) { + chainHead := ht.headSaver.Chain(chainHeadHash) + if chainHead.IsValid() { + // check if provided chain contains a block of specified height + headAtHeight, err := chainHead.HeadAtHeight(blockHeight) + if err == nil { + // we are forced to reload the block due to type mismatched caused by generics + hthAtHeight := ht.headSaver.Chain(headAtHeight.BlockHash()) + // ensure that the block was not removed from the chain by another goroutine + if hthAtHeight.IsValid() { + return hthAtHeight, nil + } + } + } + + return ht.client.HeadByNumber(ctx, big.NewInt(blockHeight)) +} + // calculateLatestFinalized - returns latest finalized block. It's expected that currentHeadNumber - is the head of // canonical chain. There is no guaranties that returned block belongs to the canonical chain. Additional verification // must be performed before usage. -func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx context.Context, currentHead HTH) (latestFinalized HTH, err error) { - if ht.config.FinalityTagEnabled() && !ht.htConfig.FinalityTagBypass() { - latestFinalized, err = ht.client.LatestFinalizedBlock(ctx) +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx context.Context, currentHead HTH, finalityTagBypass bool) (HTH, error) { + if ht.config.FinalityTagEnabled() && !finalityTagBypass { + latestFinalized, err := ht.client.LatestFinalizedBlock(ctx) if err != nil { return latestFinalized, fmt.Errorf("failed to get latest finalized block: %w", err) } @@ -349,22 +401,22 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx cont return latestFinalized, fmt.Errorf("failed to get valid latest finalized block") } - if currentHead.BlockNumber()-latestFinalized.BlockNumber() > int64(ht.htConfig.MaxAllowedFinalityDepth()) { - return latestFinalized, fmt.Errorf("gap between latest finalized block (%d) and current head (%d) is too large (> %d)", - latestFinalized.BlockNumber(), currentHead.BlockNumber(), ht.htConfig.MaxAllowedFinalityDepth()) + if ht.config.FinalizedBlockOffset() == 0 { + return latestFinalized, nil } - return latestFinalized, nil + finalizedBlockNumber := max(latestFinalized.BlockNumber()-int64(ht.config.FinalizedBlockOffset()), 0) + return ht.getHeadAtHeight(ctx, latestFinalized.BlockHash(), finalizedBlockNumber) } // no need to make an additional RPC call on chains with instant finality - if ht.config.FinalityDepth() == 0 { + if ht.config.FinalityDepth() == 0 && ht.config.FinalizedBlockOffset() == 0 { return currentHead, nil } - finalizedBlockNumber := currentHead.BlockNumber() - int64(ht.config.FinalityDepth()) + finalizedBlockNumber := currentHead.BlockNumber() - int64(ht.config.FinalityDepth()) - int64(ht.config.FinalizedBlockOffset()) if finalizedBlockNumber <= 0 { finalizedBlockNumber = 0 } - return ht.client.HeadByNumber(ctx, big.NewInt(finalizedBlockNumber)) + return ht.getHeadAtHeight(ctx, currentHead.BlockHash(), finalizedBlockNumber) } // backfill fetches all missing heads up until the latestFinalizedHead diff --git a/common/headtracker/mocks/head_broadcaster.go b/common/headtracker/mocks/head_broadcaster.go index c3a9fba97b7..e11adb715fd 100644 --- a/common/headtracker/mocks/head_broadcaster.go +++ b/common/headtracker/mocks/head_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/headtracker/mocks/head_trackable.go b/common/headtracker/mocks/head_trackable.go index 417152d8cbd..9b70938512c 100644 --- a/common/headtracker/mocks/head_trackable.go +++ b/common/headtracker/mocks/head_trackable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/headtracker/mocks/head_tracker.go b/common/headtracker/mocks/head_tracker.go index 2321c3bfdca..b02c605f535 100644 --- a/common/headtracker/mocks/head_tracker.go +++ b/common/headtracker/mocks/head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -15,17 +15,17 @@ type HeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { mock.Mock } -// Backfill provides a mock function with given fields: ctx, headWithChain, latestFinalized -func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain H, latestFinalized H) error { - ret := _m.Called(ctx, headWithChain, latestFinalized) +// Backfill provides a mock function with given fields: ctx, headWithChain +func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain H) error { + ret := _m.Called(ctx, headWithChain) if len(ret) == 0 { panic("no return value specified for Backfill") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, H, H) error); ok { - r0 = rf(ctx, headWithChain, latestFinalized) + if rf, ok := ret.Get(0).(func(context.Context, H) error); ok { + r0 = rf(ctx, headWithChain) } else { r0 = ret.Error(0) } @@ -71,6 +71,41 @@ func (_m *HeadTracker[H, BLOCK_HASH]) HealthReport() map[string]error { return r0 } +// LatestAndFinalizedBlock provides a mock function with given fields: ctx +func (_m *HeadTracker[H, BLOCK_HASH]) LatestAndFinalizedBlock(ctx context.Context) (H, H, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for LatestAndFinalizedBlock") + } + + var r0 H + var r1 H + var r2 error + if rf, ok := ret.Get(0).(func(context.Context) (H, H, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) H); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(H) + } + + if rf, ok := ret.Get(1).(func(context.Context) H); ok { + r1 = rf(ctx) + } else { + r1 = ret.Get(1).(H) + } + + if rf, ok := ret.Get(2).(func(context.Context) error); ok { + r2 = rf(ctx) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // LatestChain provides a mock function with given fields: func (_m *HeadTracker[H, BLOCK_HASH]) LatestChain() H { ret := _m.Called() diff --git a/common/headtracker/types/config.go b/common/headtracker/types/config.go index e0eb422672d..06ad93d39d2 100644 --- a/common/headtracker/types/config.go +++ b/common/headtracker/types/config.go @@ -6,6 +6,7 @@ type Config interface { BlockEmissionIdleWarningThreshold() time.Duration FinalityDepth() uint32 FinalityTagEnabled() bool + FinalizedBlockOffset() uint32 } type HeadTrackerConfig interface { diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 502f6fe8a25..c7380b76876 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 3ed05b2caee..932b58f6430 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -7,8 +7,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -58,7 +56,7 @@ func (r *Reaper[CHAIN_ID]) Stop() { func (r *Reaper[CHAIN_ID]) runLoop() { defer close(r.chDone) - ticker := time.NewTicker(utils.WithJitter(r.txConfig.ReaperInterval())) + ticker := services.NewTicker(r.txConfig.ReaperInterval()) defer ticker.Stop() for { select { @@ -66,10 +64,9 @@ func (r *Reaper[CHAIN_ID]) runLoop() { return case <-ticker.C: r.work() - ticker.Reset(utils.WithJitter(r.txConfig.ReaperInterval())) case <-r.trigger: r.work() - ticker.Reset(utils.WithJitter(r.txConfig.ReaperInterval())) + ticker.Reset() } } } diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 8483b7a0264..d4f1b4275a1 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -9,8 +9,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -120,7 +118,7 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() er.logger.Warnw("Failed to resend unconfirmed transactions", "err", err) } - ticker := time.NewTicker(utils.WithJitter(er.interval)) + ticker := services.NewTicker(er.interval) defer ticker.Stop() for { select { diff --git a/common/txmgr/types/mocks/forwarder_manager.go b/common/txmgr/types/mocks/forwarder_manager.go index b2cf9bc9d35..366fd270151 100644 --- a/common/txmgr/types/mocks/forwarder_manager.go +++ b/common/txmgr/types/mocks/forwarder_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index f6f572a35ff..0a14acfbeda 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go index 716b3e5175a..30f58c10003 100644 --- a/common/txmgr/types/mocks/reaper_chain_config.go +++ b/common/txmgr/types/mocks/reaper_chain_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index 47614674336..692b71e739c 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index bb8fabf1a71..9c2edfa963f 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/txmgr/types/mocks/tx_strategy.go b/common/txmgr/types/mocks/tx_strategy.go index 414fdb44cb0..1034e00e545 100644 --- a/common/txmgr/types/mocks/tx_strategy.go +++ b/common/txmgr/types/mocks/tx_strategy.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/common/types/head.go b/common/types/head.go index 9d927d4f5e4..77a2a7a0dcf 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -33,6 +33,9 @@ type Head[BLOCK_HASH Hashable] interface { // If not in chain, returns the zero hash HashAtHeight(blockNum int64) BLOCK_HASH + // HeadAtHeight returns head at specified height or an error, if one does not exist in provided chain. + HeadAtHeight(blockNum int64) (Head[BLOCK_HASH], error) + // Returns the total difficulty of the block. For chains who do not have a concept of block // difficulty, return 0. BlockDifficulty() *big.Int diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 8fcd57a33c9..102368199ae 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -184,6 +184,36 @@ func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { return r0 } +// HeadAtHeight provides a mock function with given fields: blockNum +func (_m *Head[BLOCK_HASH]) HeadAtHeight(blockNum int64) (types.Head[BLOCK_HASH], error) { + ret := _m.Called(blockNum) + + if len(ret) == 0 { + panic("no return value specified for HeadAtHeight") + } + + var r0 types.Head[BLOCK_HASH] + var r1 error + if rf, ok := ret.Get(0).(func(int64) (types.Head[BLOCK_HASH], error)); ok { + return rf(blockNum) + } + if rf, ok := ret.Get(0).(func(int64) types.Head[BLOCK_HASH]); ok { + r0 = rf(blockNum) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Head[BLOCK_HASH]) + } + } + + if rf, ok := ret.Get(1).(func(int64) error); ok { + r1 = rf(blockNum) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // IsValid provides a mock function with given fields: func (_m *Head[BLOCK_HASH]) IsValid() bool { ret := _m.Called() diff --git a/common/types/mocks/subscription.go b/common/types/mocks/subscription.go index e52fafa7ca5..6abf2acdb52 100644 --- a/common/types/mocks/subscription.go +++ b/common/types/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/contracts/.prettierignore b/contracts/.prettierignore index b2c6d61c220..7c3131db424 100644 --- a/contracts/.prettierignore +++ b/contracts/.prettierignore @@ -15,7 +15,6 @@ abi artifacts foundry-artifacts foundry-cache -foundry-lib cache node_modules solc diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index ba11b396e89..c3e69464698 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -39,7 +39,7 @@ abigen: ## Build & install abigen. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.35.4 + go install github.com/vektra/mockery/v2@v2.43.2 .PHONY: foundry foundry: ## Install foundry. @@ -73,18 +73,6 @@ wrappers-all: pnpmdep mockery abigen ## Recompiles solidity contracts and their # go_generate contains a call to compile all contracts before generating wrappers go generate ../core/gethwrappers/go_generate.go -# Custom wrapper generation for OCR2VRF as their contracts do not exist in this repo -.PHONY: go-solidity-wrappers-ocr2vrf -go-solidity-wrappers-ocr2vrf: pnpmdep abigen ## Recompiles OCR2VRF solidity contracts and their go wrappers. - ./scripts/native_solc_compile_all_ocr2vrf - # replace the go:generate_disabled directive with the regular go:generate directive - sed -i '' 's/go:generate_disabled/go:generate/g' ../core/gethwrappers/ocr2vrf/go_generate.go - go generate ../core/gethwrappers/ocr2vrf - go generate ../core/internal/mocks - # put the go:generate_disabled directive back - sed -i '' 's/go:generate/go:generate_disabled/g' ../core/gethwrappers/ocr2vrf/go_generate.go - - help: @echo "" @echo " .__ .__ .__ .__ __" diff --git a/contracts/ci.json b/contracts/ci.json deleted file mode 100644 index 668c85fd4d4..00000000000 --- a/contracts/ci.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "type": "solidity", - "basePath": "./contracts/test/", - "splits": [ - { - "dir": "v0.8", - "numOfSplits": 5, - "slowTests": [ - "CronUpkeepFactory", - "AutomationRegistry2_2", - "AutomationRegistry2_3" - ] - } - ] -} diff --git a/contracts/foundry.toml b/contracts/foundry.toml index f5922c4a575..08940b4e9ff 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -7,7 +7,7 @@ src = 'src/v0.8' test = 'test/v0.8' out = 'foundry-artifacts' cache_path = 'foundry-cache' -libs = ['node_modules', 'foundry-lib'] +libs = ['node_modules'] bytecode_hash = "none" ffi = false diff --git a/contracts/scripts/native_solc_compile_all_ocr2vrf b/contracts/scripts/native_solc_compile_all_ocr2vrf deleted file mode 100755 index 755edd34f56..00000000000 --- a/contracts/scripts/native_solc_compile_all_ocr2vrf +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo " ┌──────────────────────────────────────────────┐" -echo " │ Compiling OCR2 VRF contracts... │" -echo " └──────────────────────────────────────────────┘" - -SOLC_VERSION="0.8.19" -OPTIMIZE_RUNS=1000000 -# The VRF contracts are not contained in the `chainlink` repository. -# Change me. -FOLDER="ocr2vrf-origin" - -echo "Compiling OCR2VRF contracts..." - -SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt - -solc-select install $SOLC_VERSION -solc-select use $SOLC_VERSION -export SOLC_VERSION=$SOLC_VERSION - - -compileContract () { - local contract - contract=$(basename "$1" ".sol") - - solc --overwrite --optimize --optimize-runs "$2" --metadata-hash none \ - -o "$ROOT"/contracts/solc/v0.8.19/"$contract" \ - --abi --bin \ - --allow-paths "$ROOT"/../$FOLDER/contracts \ - "$ROOT"/"$1" -} - -# OCR2VRF -compileContract ../$FOLDER/contracts/DKG.sol $OPTIMIZE_RUNS -compileContract ../$FOLDER/contracts/VRFBeacon.sol $OPTIMIZE_RUNS -compileContract ../$FOLDER/contracts/VRFCoordinator.sol 1 -compileContract ../$FOLDER/contracts/test/TestBeaconVRFConsumer.sol $OPTIMIZE_RUNS -compileContract ../$FOLDER/contracts/test/LoadTestBeaconVRFConsumer.sol $OPTIMIZE_RUNS diff --git a/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol b/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol index 56df5078672..6b150dc5d74 100644 --- a/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol +++ b/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol @@ -1010,10 +1010,7 @@ contract CapabilitiesRegistry is OwnerIsCreator, TypeAndVersionInterface { /// beforeCapabilityConfigSet if ( capability.configurationContract.code.length == 0 || - !IERC165(capability.configurationContract).supportsInterface( - ICapabilityConfiguration.getCapabilityConfiguration.selector ^ - ICapabilityConfiguration.beforeCapabilityConfigSet.selector - ) + !IERC165(capability.configurationContract).supportsInterface(type(ICapabilityConfiguration).interfaceId) ) revert InvalidCapabilityConfigurationContractInterface(capability.configurationContract); } s_capabilities[hashedCapabilityId] = capability; diff --git a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index 1d741280851..86578fb1400 100644 --- a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -232,6 +232,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _fulfillmentFlatFeeLinkDiscountPPM is the flat fee discount in millionths of native that VRFCoordinatorV2Plus * charges for link payment. */ + /// @dev This function while having only 12 parameters is causing a Stack too deep error when running forge coverage. function setConfig( uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverheadNative, diff --git a/contracts/src/v0.8/vrf/test/BatchVRFCoordinatorV2Plus.t.sol b/contracts/src/v0.8/vrf/test/BatchVRFCoordinatorV2Plus.t.sol new file mode 100644 index 00000000000..298af8c76e3 --- /dev/null +++ b/contracts/src/v0.8/vrf/test/BatchVRFCoordinatorV2Plus.t.sol @@ -0,0 +1,178 @@ +pragma solidity 0.8.19; + +import {console} from "forge-std/console.sol"; +import {VRF} from "../VRF.sol"; +import {VRFTypes} from "../VRFTypes.sol"; +import {BatchVRFCoordinatorV2Plus} from "../dev/BatchVRFCoordinatorV2Plus.sol"; +import {VRFV2PlusClient} from "../dev/libraries/VRFV2PlusClient.sol"; +import {VRFCoordinatorV2_5} from "../dev/VRFCoordinatorV2_5.sol"; +import "./BaseTest.t.sol"; +import {FixtureVRFCoordinatorV2_5} from "./FixtureVRFCoordinatorV2_5.t.sol"; + +contract BatchVRFCoordinatorV2PlusTest is FixtureVRFCoordinatorV2_5 { + BatchVRFCoordinatorV2Plus private s_batchCoordinator; + + event RandomWordsFulfilled( + uint256 indexed requestId, + uint256 outputSeed, + uint256 indexed subId, + uint96 payment, + bool nativePayment, + bool success, + bool onlyPremium + ); + + function setUp() public override { + FixtureVRFCoordinatorV2_5.setUp(); + + s_batchCoordinator = new BatchVRFCoordinatorV2Plus(address(s_coordinator)); + } + + function test_fulfillRandomWords() public { + _setUpConfig(); + _setUpProvingKey(); + _setUpSubscription(); + + uint32 requestBlock = 10; + vm.roll(requestBlock); + + vm.startPrank(SUBSCRIPTION_OWNER); + vm.deal(SUBSCRIPTION_OWNER, 10 ether); + s_coordinator.fundSubscriptionWithNative{value: 10 ether}(s_subId); + + // Request random words. + s_consumer.requestRandomWords(CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS, NUM_WORDS, VRF_KEY_HASH, true); + vm.stopPrank(); + + // Move on to the next block. + // Store the previous block's blockhash. + vm.roll(requestBlock + 1); + s_bhs.store(requestBlock); + + VRFTypes.Proof[] memory proofs = new VRFTypes.Proof[](2); + VRFTypes.RequestCommitmentV2Plus[] memory rcs = new VRFTypes.RequestCommitmentV2Plus[](2); + + // Proof generated via the generate-proof-v2-plus script command. Example usage: + // _printGenerateProofV2PlusCommand(address(s_consumer), 1, requestBlock, true); + /* + go run . generate-proof-v2-plus \ + -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ + -pre-seed 33855227690351884611579800220581891477580182035146587491531555927634180294480 \ + -block-hash 0x0a \ + -block-num 10 \ + -sender 0xdc90e8ce61c1af8a638b95264037c8e67ee5765c \ + -native-payment true + + */ + proofs[0] = VRFTypes.Proof({ + pk: [ + 72488970228380509287422715226575535698893157273063074627791787432852706183111, + 62070622898698443831883535403436258712770888294397026493185421712108624767191 + ], + gamma: [ + 80420391742429647505172101941811820476888293644816377569181566466584288434705, + 24046736031266889997051641830469514057863365715722268340801477580836256044582 + ], + c: 74775128390693502914275156263410881155583102046081919417827483535122161050585, + s: 69563235412360165148368009853509434870917653835330501139204071967997764190111, + seed: 33855227690351884611579800220581891477580182035146587491531555927634180294480, + uWitness: 0xfB0663eaf48785540dE0FD0F837FD9c09BF4B80A, + cGammaWitness: [ + 53711159452748734758194447734939737695995909567499536035707522847057731697403, + 113650002631484103366420937668971311744887820666944514581352028601506700116835 + ], + sHashWitness: [ + 89656531714223714144489731263049239277719465105516547297952288438117443488525, + 90859682705760125677895017864538514058733199985667976488434404721197234427011 + ], + zInv: 97275608653505690744303242942631893944856831559408852202478373762878300587548 + }); + rcs[0] = VRFTypes.RequestCommitmentV2Plus({ + blockNum: requestBlock, + subId: s_subId, + callbackGasLimit: CALLBACK_GAS_LIMIT, + numWords: 1, + sender: address(s_consumer), + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})) + }); + + VRFCoordinatorV2_5.Output memory output = s_coordinator.getRandomnessFromProofExternal( + abi.decode(abi.encode(proofs[0]), (VRF.Proof)), + rcs[0] + ); + + requestBlock = 20; + vm.roll(requestBlock); + + vm.startPrank(SUBSCRIPTION_OWNER); + s_linkToken.setBalance(address(SUBSCRIPTION_OWNER), 10 ether); + s_linkToken.transferAndCall(address(s_coordinator), 10 ether, abi.encode(s_subId)); + + // Request random words. + s_consumer1.requestRandomWords(CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS, NUM_WORDS, VRF_KEY_HASH, false); + vm.stopPrank(); + + // Move on to the next block. + // Store the previous block's blockhash. + vm.roll(requestBlock + 1); + s_bhs.store(requestBlock); + + // Proof generated via the generate-proof-v2-plus script command. Example usage: + // _printGenerateProofV2PlusCommand(address(s_consumer1), 1, requestBlock, false); + /* + go run . generate-proof-v2-plus \ + -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ + -pre-seed 76568185840201037774581758921393822690942290841865097674309745036496166431060 \ + -block-hash 0x14 \ + -block-num 20 \ + -sender 0x2f1c0761d6e4b1e5f01968d6c746f695e5f3e25d \ + -native-payment false + */ + proofs[1] = VRFTypes.Proof({ + pk: [ + 72488970228380509287422715226575535698893157273063074627791787432852706183111, + 62070622898698443831883535403436258712770888294397026493185421712108624767191 + ], + gamma: [ + 21323932463597506192387578758854201988004673105893105492473194972397109828006, + 96834737826889397196571646974355352644437196500310392203712129010026003355112 + ], + c: 8775807990949224376582975115621037245862755412370175152581490650310350359728, + s: 6805708577951013810918872616271445638109899206333819877111740872779453350091, + seed: 76568185840201037774581758921393822690942290841865097674309745036496166431060, + uWitness: 0xE82fF24Fecfbe73d682f38308bE3E039Dfabdf5c, + cGammaWitness: [ + 92810770919624535241476539842820168209710445519252592382122118536598338376923, + 17271305664006119131434661141858450289379246199095231636439133258170648418554 + ], + sHashWitness: [ + 29540023305939374439696120003978246982707698669656874393367212257432197207536, + 93902323936532381028323379401739289810874348405259732508442252936582467730050 + ], + zInv: 88845170436601946907659333156418518556235340365885668267853966404617557948692 + }); + rcs[1] = VRFTypes.RequestCommitmentV2Plus({ + blockNum: requestBlock, + subId: s_subId, + callbackGasLimit: CALLBACK_GAS_LIMIT, + numWords: 1, + sender: address(s_consumer1), + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})) + }); + + VRFCoordinatorV2_5.Output memory output1 = s_coordinator.getRandomnessFromProofExternal( + abi.decode(abi.encode(proofs[1]), (VRF.Proof)), + rcs[1] + ); + + // The payments are NOT pre-calculated and simply copied from the actual event. + // We can assert and ignore the payment field but the code will be considerably longer. + vm.expectEmit(true, true, false, true, address(s_coordinator)); + emit RandomWordsFulfilled(output.requestId, output.randomness, s_subId, 500000000000142215, true, true, false); + vm.expectEmit(true, true, false, true, address(s_coordinator)); + emit RandomWordsFulfilled(output1.requestId, output1.randomness, s_subId, 800000000000304103, false, true, false); + + // Fulfill the requests. + s_batchCoordinator.fulfillRandomWords(proofs, rcs); + } +} diff --git a/contracts/src/v0.8/vrf/test/FixtureVRFCoordinatorV2_5.t.sol b/contracts/src/v0.8/vrf/test/FixtureVRFCoordinatorV2_5.t.sol new file mode 100644 index 00000000000..c1c2c7eb27c --- /dev/null +++ b/contracts/src/v0.8/vrf/test/FixtureVRFCoordinatorV2_5.t.sol @@ -0,0 +1,134 @@ +pragma solidity ^0.8.19; + +import {console} from "forge-std/console.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import {VRF} from "../VRF.sol"; +import {VRFTypes} from "../VRFTypes.sol"; +import {BlockhashStore} from "../dev/BlockhashStore.sol"; +import {VRFV2PlusClient} from "../dev/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFV2PlusConsumerExample} from "../dev/testhelpers/VRFV2PlusConsumerExample.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import "./BaseTest.t.sol"; + +contract FixtureVRFCoordinatorV2_5 is BaseTest, VRF { + address internal SUBSCRIPTION_OWNER = makeAddr("SUBSCRIPTION_OWNER"); + + uint64 internal constant GAS_LANE_MAX_GAS = 5000 gwei; + uint16 internal constant MIN_CONFIRMATIONS = 0; + uint32 internal constant CALLBACK_GAS_LIMIT = 1_000_000; + uint32 internal constant NUM_WORDS = 1; + + // VRF KeyV2 generated from a node; not sensitive information. + // The secret key used to generate this key is: 10. + bytes internal constant VRF_UNCOMPRESSED_PUBLIC_KEY = + hex"a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7"; + bytes internal constant VRF_COMPRESSED_PUBLIC_KEY = + hex"a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c701"; + bytes32 internal constant VRF_KEY_HASH = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; + + BlockhashStore internal s_bhs; + ExposedVRFCoordinatorV2_5 internal s_coordinator; + + // Use multiple consumers because VRFV2PlusConsumerExample cannot have multiple pending requests. + uint256 internal s_subId; + VRFV2PlusConsumerExample internal s_consumer; + VRFV2PlusConsumerExample internal s_consumer1; + + MockLinkToken internal s_linkToken; + MockV3Aggregator internal s_linkNativeFeed; + + function setUp() public virtual override { + BaseTest.setUp(); + vm.stopPrank(); + + vm.startPrank(OWNER); + s_bhs = new BlockhashStore(); + + // Deploy coordinator. + s_coordinator = new ExposedVRFCoordinatorV2_5(address(s_bhs)); + s_linkToken = new MockLinkToken(); + s_linkNativeFeed = new MockV3Aggregator(18, 500000000000000000); // .5 ETH (good for testing) + + // Configure the coordinator. + s_coordinator.setLINKAndLINKNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); + vm.stopPrank(); + + // Deploy consumers. + vm.startPrank(SUBSCRIPTION_OWNER); + s_consumer = new VRFV2PlusConsumerExample(address(s_coordinator), address(s_linkToken)); + s_consumer1 = new VRFV2PlusConsumerExample(address(s_coordinator), address(s_linkToken)); + vm.stopPrank(); + } + + function _setUpConfig() internal { + vm.prank(OWNER); + s_coordinator.setConfig( + 0, // minRequestConfirmations + 2_500_000, // maxGasLimit + 1, // stalenessSeconds + 50_000, // gasAfterPaymentCalculation + 50000000000000000, // fallbackWeiPerUnitLink + 500_000, // fulfillmentFlatFeeNativePPM + 100_000, // fulfillmentFlatFeeLinkDiscountPPM + 15, // nativePremiumPercentage + 10 // linkPremiumPercentage + ); + } + + function _setUpProvingKey() internal { + uint256[2] memory uncompressedKeyParts = this._getProvingKeyParts(VRF_UNCOMPRESSED_PUBLIC_KEY); + vm.prank(OWNER); + s_coordinator.registerProvingKey(uncompressedKeyParts, GAS_LANE_MAX_GAS); + } + + function _setUpSubscription() internal { + vm.startPrank(SUBSCRIPTION_OWNER); + s_subId = s_coordinator.createSubscription(); + s_coordinator.addConsumer(s_subId, address(s_consumer)); + s_consumer.setSubId(s_subId); + s_coordinator.addConsumer(s_subId, address(s_consumer1)); + s_consumer1.setSubId(s_subId); + vm.stopPrank(); + } + + // note: Call this function via this.getProvingKeyParts to be able to pass memory as calldata and + // index over the byte array. + function _getProvingKeyParts(bytes calldata uncompressedKey) public pure returns (uint256[2] memory) { + uint256 keyPart1 = uint256(bytes32(uncompressedKey[0:32])); + uint256 keyPart2 = uint256(bytes32(uncompressedKey[32:64])); + return [keyPart1, keyPart2]; + } + + /** + * Prints the command to generate a proof for a VRF request. + * + * This function provides a convenient way to generate the proof off-chain to be copied into the tests. + * + * An example of the command looks like this: + * go run . generate-proof-v2-plus \ + * -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ + * -pre-seed 76568185840201037774581758921393822690942290841865097674309745036496166431060 \ + * -block-hash 0x14 \ + * -block-num 20 \ + * -sender 0x2f1c0761d6e4b1e5f01968d6c746f695e5f3e25d \ + * -native-payment false + */ + function _printGenerateProofV2PlusCommand( + address sender, + uint64 nonce, + uint256 requestBlock, + bool nativePayment + ) internal { + (, uint256 preSeed) = s_coordinator.computeRequestIdExternal(VRF_KEY_HASH, sender, s_subId, nonce); + + console.log("go run . generate-proof-v2-plus \\"); + console.log(string.concat(" -key-hash ", Strings.toHexString(uint256(VRF_KEY_HASH)), " \\")); + console.log(string.concat(" -pre-seed ", Strings.toString(preSeed), " \\")); + console.log(string.concat(" -block-hash ", Strings.toHexString(uint256(blockhash(requestBlock))), " \\")); + console.log(string.concat(" -block-num ", Strings.toString(requestBlock), " \\")); + console.log(string.concat(" -sender ", Strings.toHexString(sender), " \\")); + console.log(string.concat(" -native-payment ", nativePayment ? "true" : "false")); + } +} diff --git a/core/bridges/mocks/orm.go b/core/bridges/mocks/orm.go index cda12a9045d..db8553fb215 100644 --- a/core/bridges/mocks/orm.go +++ b/core/bridges/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/launcher.go b/core/capabilities/launcher.go index e4f7f480f3a..c6846ecd5a9 100644 --- a/core/capabilities/launcher.go +++ b/core/capabilities/launcher.go @@ -97,7 +97,7 @@ func (w *launcher) LocalNode(ctx context.Context) (capabilities.Node, error) { return w.localNode, errors.New("unable to get local node: peerWrapper hasn't started yet") } - if w.localNode.WorkflowDON.ID == "" { + if w.localNode.WorkflowDON.ID == 0 { return w.localNode, errors.New("unable to get local node: waiting for initial call from syncer") } @@ -113,7 +113,7 @@ func (w *launcher) updateLocalNode(state registrysyncer.State) { for _, p := range d.NodeP2PIds { if p == pid { if d.AcceptsWorkflows { - if workflowDON.ID == "" { + if workflowDON.ID == 0 { workflowDON = *toDONInfo(d) w.lggr.Debug("Workflow DON identified: %+v", workflowDON) } else { @@ -353,7 +353,7 @@ func (w *launcher) addToRegistryAndSetDispatcher(ctx context.Context, capability err = w.dispatcher.SetReceiver( fullCapID, - fmt.Sprint(don.Id), + don.Id, capability, ) if err != nil { @@ -373,9 +373,9 @@ var ( ) func (w *launcher) exposeCapabilities(ctx context.Context, myPeerID p2ptypes.PeerID, don kcr.CapabilitiesRegistryDONInfo, state registrysyncer.State, remoteWorkflowDONs []kcr.CapabilitiesRegistryDONInfo) error { - idsToDONs := map[string]capabilities.DON{} + idsToDONs := map[uint32]capabilities.DON{} for _, d := range remoteWorkflowDONs { - idsToDONs[fmt.Sprint(d.Id)] = *toDONInfo(d) + idsToDONs[d.Id] = *toDONInfo(d) } for _, c := range don.CapabilityConfigurations { @@ -465,7 +465,7 @@ func (w *launcher) addReceiver(ctx context.Context, capability kcr.CapabilitiesR } w.lggr.Debugw("Enabling external access for capability", "id", fullCapID, "donID", don.Id) - err = w.dispatcher.SetReceiver(fullCapID, fmt.Sprint(don.Id), receiver) + err = w.dispatcher.SetReceiver(fullCapID, don.Id, receiver) if err != nil { return fmt.Errorf("failed to set receiver: %w", err) } @@ -502,9 +502,10 @@ func toDONInfo(don kcr.CapabilitiesRegistryDONInfo) *capabilities.DON { } return &capabilities.DON{ - ID: fmt.Sprint(don.Id), - Members: peerIDs, - F: don.F, + ID: don.Id, + ConfigVersion: don.ConfigCount, + Members: peerIDs, + F: don.F, } } diff --git a/core/capabilities/launcher_test.go b/core/capabilities/launcher_test.go index c29e5ebf38c..a2d1c601694 100644 --- a/core/capabilities/launcher_test.go +++ b/core/capabilities/launcher_test.go @@ -3,7 +3,6 @@ package capabilities import ( "context" "crypto/rand" - "fmt" "testing" "github.com/stretchr/testify/assert" @@ -178,8 +177,8 @@ func TestLauncher_WiresUpExternalCapabilities(t *testing.T) { registry, ) - dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(dID), mock.AnythingOfType("*remote.triggerPublisher")).Return(nil) - dispatcher.On("SetReceiver", fullTargetID, fmt.Sprint(dID), mock.AnythingOfType("*target.server")).Return(nil) + dispatcher.On("SetReceiver", fullTriggerCapID, dID, mock.AnythingOfType("*remote.triggerPublisher")).Return(nil) + dispatcher.On("SetReceiver", fullTargetID, dID, mock.AnythingOfType("*target.server")).Return(nil) err = launcher.Launch(ctx, state) require.NoError(t, err) @@ -428,8 +427,8 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDON(t *testing.T) { registry, ) - dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(capDonID), mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) - dispatcher.On("SetReceiver", fullTargetID, fmt.Sprint(capDonID), mock.AnythingOfType("*target.client")).Return(nil) + dispatcher.On("SetReceiver", fullTriggerCapID, capDonID, mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) + dispatcher.On("SetReceiver", fullTargetID, capDonID, mock.AnythingOfType("*target.client")).Return(nil) err = launcher.Launch(ctx, state) require.NoError(t, err) @@ -586,7 +585,7 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilitie registry, ) - dispatcher.On("SetReceiver", fullTriggerCapID, fmt.Sprint(triggerCapDonID), mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) + dispatcher.On("SetReceiver", fullTriggerCapID, triggerCapDonID, mock.AnythingOfType("*remote.triggerSubscriber")).Return(nil) err = launcher.Launch(ctx, state) require.NoError(t, err) @@ -634,7 +633,7 @@ func TestLauncher_LocalNode(t *testing.T) { IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ registrysyncer.DonID(dID): { Id: dID, - ConfigCount: uint32(0), + ConfigCount: uint32(2), F: uint8(1), IsPublic: true, AcceptsWorkflows: true, @@ -680,9 +679,10 @@ func TestLauncher_LocalNode(t *testing.T) { require.NoError(t, err) don := capabilities.DON{ - ID: fmt.Sprintf("%d", dID), - Members: toPeerIDs(workflowDonNodes), - F: 1, + ID: dID, + ConfigVersion: 2, + Members: toPeerIDs(workflowDonNodes), + F: 1, } expectedNode := capabilities.Node{ PeerID: &pid, diff --git a/core/capabilities/remote/dispatcher.go b/core/capabilities/remote/dispatcher.go index b91211b5bf5..90fca50b22c 100644 --- a/core/capabilities/remote/dispatcher.go +++ b/core/capabilities/remote/dispatcher.go @@ -35,7 +35,7 @@ type dispatcher struct { type key struct { capId string - donId string + donId uint32 } var _ services.Service = &dispatcher{} @@ -88,13 +88,13 @@ type receiver struct { ch chan *remotetypes.MessageBody } -func (d *dispatcher) SetReceiver(capabilityId string, donId string, rec remotetypes.Receiver) error { +func (d *dispatcher) SetReceiver(capabilityId string, donId uint32, rec remotetypes.Receiver) error { d.mu.Lock() defer d.mu.Unlock() k := key{capabilityId, donId} _, ok := d.receivers[k] if ok { - return fmt.Errorf("receiver already exists for capability %s and don %s", capabilityId, donId) + return fmt.Errorf("receiver already exists for capability %s and don %d", capabilityId, donId) } receiverCh := make(chan *remotetypes.MessageBody, receiverBufferSize) @@ -123,7 +123,7 @@ func (d *dispatcher) SetReceiver(capabilityId string, donId string, rec remotety return nil } -func (d *dispatcher) RemoveReceiver(capabilityId string, donId string) { +func (d *dispatcher) RemoveReceiver(capabilityId string, donId uint32) { d.mu.Lock() defer d.mu.Unlock() @@ -181,7 +181,7 @@ func (d *dispatcher) receive() { } receiverQueueUsage := float64(len(receiver.ch)) / receiverBufferSize - capReceiveChannelUsage.WithLabelValues(k.capId, k.donId).Set(receiverQueueUsage) + capReceiveChannelUsage.WithLabelValues(k.capId, fmt.Sprint(k.donId)).Set(receiverQueueUsage) select { case receiver.ch <- body: default: diff --git a/core/capabilities/remote/target/client_test.go b/core/capabilities/remote/target/client_test.go index 64b824d74d4..6d26b51b8ae 100644 --- a/core/capabilities/remote/target/client_test.go +++ b/core/capabilities/remote/target/client_test.go @@ -33,9 +33,9 @@ func Test_Client_DonTopologies(t *testing.T) { responseTest := func(t *testing.T, responseCh <-chan commoncap.CapabilityResponse, responseError error) { require.NoError(t, responseError) response := <-responseCh - responseValue, err := response.Value.Unwrap() + mp, err := response.Value.Unwrap() require.NoError(t, err) - assert.Equal(t, "aValue1", responseValue.(string)) + assert.Equal(t, "aValue1", mp.(map[string]any)["response"].(string)) } capability := &TestCapability{} @@ -64,9 +64,9 @@ func Test_Client_TransmissionSchedules(t *testing.T) { responseTest := func(t *testing.T, responseCh <-chan commoncap.CapabilityResponse, responseError error) { require.NoError(t, responseError) response := <-responseCh - responseValue, err := response.Value.Unwrap() + mp, err := response.Value.Unwrap() require.NoError(t, err) - assert.Equal(t, "aValue1", responseValue.(string)) + assert.Equal(t, "aValue1", mp.(map[string]any)["response"].(string)) } capability := &TestCapability{} @@ -130,7 +130,7 @@ func testClient(ctx context.Context, t *testing.T, numWorkflowPeers int, workflo } capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 1, Members: capabilityPeers, F: capabilityDonF, } @@ -149,7 +149,7 @@ func testClient(ctx context.Context, t *testing.T, numWorkflowPeers int, workflo workflowDonInfo := commoncap.DON{ Members: workflowPeers, - ID: "workflow-don", + ID: 2, } broker := newTestAsyncMessageBroker(t, 100) @@ -259,7 +259,7 @@ func (t *clientTestServer) Receive(_ context.Context, msg *remotetypes.MessageBo for receiver := range t.messageIDToSenders[messageID] { var responseMsg = &remotetypes.MessageBody{ CapabilityId: "cap_id@1.0.0", - CapabilityDonId: "capability-don", + CapabilityDonId: 1, CallerDonId: t.workflowDonInfo.ID, Method: remotetypes.MethodExecute, MessageId: []byte(messageID), diff --git a/core/capabilities/remote/target/endtoend_test.go b/core/capabilities/remote/target/endtoend_test.go index d5305afeb32..c01b8d99a4f 100644 --- a/core/capabilities/remote/target/endtoend_test.go +++ b/core/capabilities/remote/target/endtoend_test.go @@ -74,9 +74,9 @@ func Test_RemoteTargetCapability_TransmissionSchedules(t *testing.T) { responseTest := func(t *testing.T, responseCh <-chan commoncap.CapabilityResponse, responseError error) { require.NoError(t, responseError) response := <-responseCh - responseValue, err := response.Value.Unwrap() + mp, err := response.Value.Unwrap() require.NoError(t, err) - assert.Equal(t, "aValue1", responseValue.(string)) + assert.Equal(t, "aValue1", mp.(map[string]any)["response"].(string)) } transmissionSchedule, err := values.NewMap(map[string]any{ @@ -106,9 +106,9 @@ func Test_RemoteTargetCapability_DonTopologies(t *testing.T) { responseTest := func(t *testing.T, responseCh <-chan commoncap.CapabilityResponse, responseError error) { require.NoError(t, responseError) response := <-responseCh - responseValue, err := response.Value.Unwrap() + mp, err := response.Value.Unwrap() require.NoError(t, err) - assert.Equal(t, "aValue1", responseValue.(string)) + assert.Equal(t, "aValue1", mp.(map[string]any)["response"].(string)) } transmissionSchedule, err := values.NewMap(map[string]any{ @@ -191,7 +191,7 @@ func testRemoteTarget(ctx context.Context, t *testing.T, underlying commoncap.Ta require.NoError(t, capabilityPeerID.UnmarshalText([]byte(NewPeerID()))) capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 2, Members: capabilityPeers, F: capabilityDonF, } @@ -212,13 +212,13 @@ func testRemoteTarget(ctx context.Context, t *testing.T, underlying commoncap.Ta workflowDonInfo := commoncap.DON{ Members: workflowPeers, - ID: "workflow-don", + ID: 1, F: workflowDonF, } broker := newTestAsyncMessageBroker(t, 1000) - workflowDONs := map[string]commoncap.DON{ + workflowDONs := map[uint32]commoncap.DON{ workflowDonInfo.ID: workflowDonInfo, } @@ -380,10 +380,10 @@ func (t *nodeDispatcher) Send(peerID p2ptypes.PeerID, msgBody *remotetypes.Messa return nil } -func (t *nodeDispatcher) SetReceiver(capabilityId string, donId string, receiver remotetypes.Receiver) error { +func (t *nodeDispatcher) SetReceiver(capabilityId string, donId uint32, receiver remotetypes.Receiver) error { return nil } -func (t *nodeDispatcher) RemoveReceiver(capabilityId string, donId string) {} +func (t *nodeDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} type abstractTestCapability struct { } @@ -409,8 +409,12 @@ func (t TestCapability) Execute(ctx context.Context, request commoncap.Capabilit value := request.Inputs.Underlying["executeValue1"] + response, err := values.NewMap(map[string]any{"response": value}) + if err != nil { + return nil, err + } ch <- commoncap.CapabilityResponse{ - Value: value, + Value: response, } return ch, nil diff --git a/core/capabilities/remote/target/request/client_request_test.go b/core/capabilities/remote/target/request/client_request_test.go index a053623cd2c..c20c24a5508 100644 --- a/core/capabilities/remote/target/request/client_request_test.go +++ b/core/capabilities/remote/target/request/client_request_test.go @@ -30,7 +30,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { } capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 1, Members: capabilityPeers, F: 1, } @@ -50,7 +50,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { workflowDonInfo := commoncap.DON{ Members: workflowPeers, - ID: "workflow-don", + ID: 2, } executeInputs, err := values.NewMap( @@ -75,8 +75,10 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { Config: transmissionSchedule, } + m, err := values.NewMap(map[string]any{"response": "response1"}) + require.NoError(t, err) capabilityResponse := commoncap.CapabilityResponse{ - Value: values.NewString("response1"), + Value: m, Err: nil, } @@ -106,8 +108,10 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { require.NoError(t, err) + nm, err := values.NewMap(map[string]any{"response": "response2"}) + require.NoError(t, err) capabilityResponse2 := commoncap.CapabilityResponse{ - Value: values.NewString("response2"), + Value: nm, Err: nil, } @@ -297,8 +301,9 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { require.NoError(t, err) response := <-request.ResponseChan() + resp := response.Value.Underlying["response"] - assert.Equal(t, response.Value, values.NewString("response1")) + assert.Equal(t, resp, values.NewString("response1")) }) } @@ -306,11 +311,11 @@ type clientRequestTestDispatcher struct { msgs chan *types.MessageBody } -func (t *clientRequestTestDispatcher) SetReceiver(capabilityId string, donId string, receiver types.Receiver) error { +func (t *clientRequestTestDispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { return nil } -func (t *clientRequestTestDispatcher) RemoveReceiver(capabilityId string, donId string) {} +func (t *clientRequestTestDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} func (t *clientRequestTestDispatcher) Send(peerID p2ptypes.PeerID, msgBody *types.MessageBody) error { t.msgs <- msgBody diff --git a/core/capabilities/remote/target/request/server_request.go b/core/capabilities/remote/target/request/server_request.go index bb84fda4ac0..25d88d2192a 100644 --- a/core/capabilities/remote/target/request/server_request.go +++ b/core/capabilities/remote/target/request/server_request.go @@ -27,7 +27,7 @@ type ServerRequest struct { capabilityPeerId p2ptypes.PeerID capabilityID string - capabilityDonID string + capabilityDonID uint32 dispatcher types.Dispatcher @@ -47,7 +47,7 @@ type ServerRequest struct { lggr logger.Logger } -func NewServerRequest(capability capabilities.TargetCapability, capabilityID string, capabilityDonID string, capabilityPeerId p2ptypes.PeerID, +func NewServerRequest(capability capabilities.TargetCapability, capabilityID string, capabilityDonID uint32, capabilityPeerId p2ptypes.PeerID, callingDon commoncap.DON, requestMessageID string, dispatcher types.Dispatcher, requestTimeout time.Duration, lggr logger.Logger) *ServerRequest { return &ServerRequest{ diff --git a/core/capabilities/remote/target/request/server_request_test.go b/core/capabilities/remote/target/request/server_request_test.go index fe3fdd713b5..053cba7064d 100644 --- a/core/capabilities/remote/target/request/server_request_test.go +++ b/core/capabilities/remote/target/request/server_request_test.go @@ -33,7 +33,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { callingDon := commoncap.DON{ Members: workflowPeers, - ID: "workflow-don", + ID: 1, F: 1, } @@ -58,7 +58,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { require.NoError(t, err) t.Run("Send duplicate message", func(t *testing.T) { - req := request.NewServerRequest(capability, "capabilityID", "capabilityDonID", + req := request.NewServerRequest(capability, "capabilityID", 2, capabilityPeerID, callingDon, "requestMessageID", dispatcher, 10*time.Minute, lggr) err := sendValidRequest(req, workflowPeers, capabilityPeerID, rawRequest) @@ -68,7 +68,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { }) t.Run("Send message with non calling don peer", func(t *testing.T) { - req := request.NewServerRequest(capability, "capabilityID", "capabilityDonID", + req := request.NewServerRequest(capability, "capabilityID", 2, capabilityPeerID, callingDon, "requestMessageID", dispatcher, 10*time.Minute, lggr) err := sendValidRequest(req, workflowPeers, capabilityPeerID, rawRequest) @@ -81,8 +81,8 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { Receiver: capabilityPeerID[:], MessageId: []byte("workflowID" + "workflowExecutionID"), CapabilityId: "capabilityID", - CapabilityDonId: "capabilityDonID", - CallerDonId: "workflow-don", + CapabilityDonId: 2, + CallerDonId: 1, Method: types.MethodExecute, Payload: rawRequest, }) @@ -91,7 +91,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { }) t.Run("Send message invalid payload", func(t *testing.T) { - req := request.NewServerRequest(capability, "capabilityID", "capabilityDonID", + req := request.NewServerRequest(capability, "capabilityID", 2, capabilityPeerID, callingDon, "requestMessageID", dispatcher, 10*time.Minute, lggr) err := sendValidRequest(req, workflowPeers, capabilityPeerID, rawRequest) @@ -103,8 +103,8 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { Receiver: capabilityPeerID[:], MessageId: []byte("workflowID" + "workflowExecutionID"), CapabilityId: "capabilityID", - CapabilityDonId: "capabilityDonID", - CallerDonId: "workflow-don", + CapabilityDonId: 2, + CallerDonId: 1, Method: types.MethodExecute, Payload: append(rawRequest, []byte("asdf")...), }) @@ -116,7 +116,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { t.Run("Send second valid request when capability errors", func(t *testing.T) { dispatcher := &testDispatcher{} - req := request.NewServerRequest(TestErrorCapability{}, "capabilityID", "capabilityDonID", + req := request.NewServerRequest(TestErrorCapability{}, "capabilityID", 2, capabilityPeerID, callingDon, "requestMessageID", dispatcher, 10*time.Minute, lggr) err := sendValidRequest(req, workflowPeers, capabilityPeerID, rawRequest) @@ -128,8 +128,8 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { Receiver: capabilityPeerID[:], MessageId: []byte("workflowID" + "workflowExecutionID"), CapabilityId: "capabilityID", - CapabilityDonId: "capabilityDonID", - CallerDonId: "workflow-don", + CapabilityDonId: 2, + CallerDonId: 1, Method: types.MethodExecute, Payload: rawRequest, }) @@ -143,7 +143,7 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { t.Run("Send second valid request", func(t *testing.T) { dispatcher := &testDispatcher{} - request := request.NewServerRequest(capability, "capabilityID", "capabilityDonID", + request := request.NewServerRequest(capability, "capabilityID", 2, capabilityPeerID, callingDon, "requestMessageID", dispatcher, 10*time.Minute, lggr) err := sendValidRequest(request, workflowPeers, capabilityPeerID, rawRequest) @@ -155,8 +155,8 @@ func Test_ServerRequest_MessageValidation(t *testing.T) { Receiver: capabilityPeerID[:], MessageId: []byte("workflowID" + "workflowExecutionID"), CapabilityId: "capabilityID", - CapabilityDonId: "capabilityDonID", - CallerDonId: "workflow-don", + CapabilityDonId: 2, + CallerDonId: 1, Method: types.MethodExecute, Payload: rawRequest, }) @@ -179,8 +179,8 @@ func sendValidRequest(request serverRequest, workflowPeers []p2ptypes.PeerID, ca Receiver: capabilityPeerID[:], MessageId: []byte("workflowID" + "workflowExecutionID"), CapabilityId: "capabilityID", - CapabilityDonId: "capabilityDonID", - CallerDonId: "workflow-don", + CapabilityDonId: 2, + CallerDonId: 1, Method: types.MethodExecute, Payload: rawRequest, }) @@ -190,11 +190,11 @@ type testDispatcher struct { msgs []*types.MessageBody } -func (t *testDispatcher) SetReceiver(capabilityId string, donId string, receiver types.Receiver) error { +func (t *testDispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { return nil } -func (t *testDispatcher) RemoveReceiver(capabilityId string, donId string) {} +func (t *testDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} func (t *testDispatcher) Send(peerID p2ptypes.PeerID, msgBody *types.MessageBody) error { t.msgs = append(t.msgs, msgBody) @@ -225,8 +225,12 @@ func (t TestCapability) Execute(ctx context.Context, request commoncap.Capabilit value := request.Inputs.Underlying["executeValue1"] + response, err := values.NewMap(map[string]any{"response": value}) + if err != nil { + return nil, err + } ch <- commoncap.CapabilityResponse{ - Value: value, + Value: response, } return ch, nil diff --git a/core/capabilities/remote/target/server.go b/core/capabilities/remote/target/server.go index a918dd91700..1453cfc3778 100644 --- a/core/capabilities/remote/target/server.go +++ b/core/capabilities/remote/target/server.go @@ -29,7 +29,7 @@ type server struct { underlying commoncap.TargetCapability capInfo commoncap.CapabilityInfo localDonInfo commoncap.DON - workflowDONs map[string]commoncap.DON + workflowDONs map[uint32]commoncap.DON dispatcher types.Dispatcher requestIDToRequest map[string]*request.ServerRequest @@ -44,7 +44,7 @@ var _ types.Receiver = &server{} var _ services.Service = &server{} func NewServer(peerID p2ptypes.PeerID, underlying commoncap.TargetCapability, capInfo commoncap.CapabilityInfo, localDonInfo commoncap.DON, - workflowDONs map[string]commoncap.DON, dispatcher types.Dispatcher, requestTimeout time.Duration, lggr logger.Logger) *server { + workflowDONs map[uint32]commoncap.DON, dispatcher types.Dispatcher, requestTimeout time.Duration, lggr logger.Logger) *server { return &server{ underlying: underlying, peerID: peerID, diff --git a/core/capabilities/remote/target/server_test.go b/core/capabilities/remote/target/server_test.go index 3c12ce813d9..a5aa45efd06 100644 --- a/core/capabilities/remote/target/server_test.go +++ b/core/capabilities/remote/target/server_test.go @@ -112,7 +112,7 @@ func testRemoteTargetServer(ctx context.Context, t *testing.T, } capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 1, Members: capabilityPeers, F: capabilityDonF, } @@ -131,7 +131,7 @@ func testRemoteTargetServer(ctx context.Context, t *testing.T, workflowDonInfo := commoncap.DON{ Members: workflowPeers, - ID: "workflow-don", + ID: 2, F: workflowDonF, } @@ -141,7 +141,7 @@ func testRemoteTargetServer(ctx context.Context, t *testing.T, require.NoError(t, err) srvcs = append(srvcs, broker) - workflowDONs := map[string]commoncap.DON{ + workflowDONs := map[uint32]commoncap.DON{ workflowDonInfo.ID: workflowDonInfo, } @@ -219,8 +219,8 @@ func (r *serverTestClient) Execute(ctx context.Context, req commoncap.Capability for _, node := range r.capabilityDonInfo.Members { message := &remotetypes.MessageBody{ CapabilityId: "capability-id", - CapabilityDonId: "capability-don", - CallerDonId: "workflow-don", + CapabilityDonId: 1, + CallerDonId: 2, Method: remotetypes.MethodExecute, Payload: rawRequest, MessageId: []byte(messageID), diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go index 9e7fc893525..d559dc36d4b 100644 --- a/core/capabilities/remote/trigger_publisher.go +++ b/core/capabilities/remote/trigger_publisher.go @@ -25,7 +25,7 @@ type triggerPublisher struct { underlying commoncap.TriggerCapability capInfo commoncap.CapabilityInfo capDonInfo commoncap.DON - workflowDONs map[string]commoncap.DON + workflowDONs map[uint32]commoncap.DON dispatcher types.Dispatcher messageCache *messageCache[registrationKey, p2ptypes.PeerID] registrations map[registrationKey]*pubRegState @@ -36,7 +36,7 @@ type triggerPublisher struct { } type registrationKey struct { - callerDonId string + callerDonId uint32 workflowId string } @@ -48,7 +48,7 @@ type pubRegState struct { var _ types.Receiver = &triggerPublisher{} var _ services.Service = &triggerPublisher{} -func NewTriggerPublisher(config *types.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[string]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher { +func NewTriggerPublisher(config *types.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[uint32]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher { config.ApplyDefaults() return &triggerPublisher{ config: config, diff --git a/core/capabilities/remote/trigger_publisher_test.go b/core/capabilities/remote/trigger_publisher_test.go index db792fb5061..ec38b962ced 100644 --- a/core/capabilities/remote/trigger_publisher_test.go +++ b/core/capabilities/remote/trigger_publisher_test.go @@ -29,12 +29,12 @@ func TestTriggerPublisher_Register(t *testing.T) { p2 := p2ptypes.PeerID{} require.NoError(t, p2.UnmarshalText([]byte(peerID2))) capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 1, Members: []p2ptypes.PeerID{p1}, F: 0, } workflowDonInfo := commoncap.DON{ - ID: "workflow-don", + ID: 2, Members: []p2ptypes.PeerID{p2}, F: 0, } @@ -46,7 +46,7 @@ func TestTriggerPublisher_Register(t *testing.T) { MinResponsesToAggregate: 1, MessageExpiryMs: 100_000, } - workflowDONs := map[string]commoncap.DON{ + workflowDONs := map[uint32]commoncap.DON{ workflowDonInfo.ID: workflowDonInfo, } underlying := &testTrigger{ diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go index 3b819f9f3cc..782b29d41f9 100644 --- a/core/capabilities/remote/trigger_subscriber_test.go +++ b/core/capabilities/remote/trigger_subscriber_test.go @@ -18,11 +18,14 @@ import ( ) const ( - peerID1 = "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC" - peerID2 = "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8" - workflowID1 = "workflowID1" - triggerEvent1 = "triggerEvent1" - triggerEvent2 = "triggerEvent2" + peerID1 = "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC" + peerID2 = "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8" + workflowID1 = "workflowID1" +) + +var ( + triggerEvent1 = map[string]any{"event": "triggerEvent1"} + triggerEvent2 = map[string]any{"event": "triggerEvent2"} ) func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { @@ -38,12 +41,12 @@ func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { p2 := p2ptypes.PeerID{} require.NoError(t, p2.UnmarshalText([]byte(peerID2))) capDonInfo := commoncap.DON{ - ID: "capability-don", + ID: 1, Members: []p2ptypes.PeerID{p1}, F: 0, } workflowDonInfo := commoncap.DON{ - ID: "workflow-don", + ID: 2, Members: []p2ptypes.PeerID{p2}, F: 0, } @@ -77,7 +80,7 @@ func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { <-awaitRegistrationMessageCh // receive trigger event - triggerEventValue, err := values.Wrap(triggerEvent1) + triggerEventValue, err := values.NewMap(triggerEvent1) require.NoError(t, err) capResponse := commoncap.CapabilityResponse{ Value: triggerEventValue, diff --git a/core/capabilities/remote/types/messages.pb.go b/core/capabilities/remote/types/messages.pb.go index 0e51b395993..d1b86d9febb 100644 --- a/core/capabilities/remote/types/messages.pb.go +++ b/core/capabilities/remote/types/messages.pb.go @@ -138,24 +138,24 @@ type MessageBody struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - Receiver []byte `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` - Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - MessageId []byte `protobuf:"bytes,5,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // scoped to sender - CapabilityId string `protobuf:"bytes,6,opt,name=capability_id,json=capabilityId,proto3" json:"capability_id,omitempty"` - CapabilityDonId string `protobuf:"bytes,7,opt,name=capability_don_id,json=capabilityDonId,proto3" json:"capability_don_id,omitempty"` - CallerDonId string `protobuf:"bytes,8,opt,name=caller_don_id,json=callerDonId,proto3" json:"caller_don_id,omitempty"` - Method string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"` - Error Error `protobuf:"varint,10,opt,name=error,proto3,enum=remote.Error" json:"error,omitempty"` - ErrorMsg string `protobuf:"bytes,11,opt,name=errorMsg,proto3" json:"errorMsg,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + Receiver []byte `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + MessageId []byte `protobuf:"bytes,5,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // scoped to sender + CapabilityId string `protobuf:"bytes,6,opt,name=capability_id,json=capabilityId,proto3" json:"capability_id,omitempty"` + Method string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"` + Error Error `protobuf:"varint,10,opt,name=error,proto3,enum=remote.Error" json:"error,omitempty"` + ErrorMsg string `protobuf:"bytes,11,opt,name=errorMsg,proto3" json:"errorMsg,omitempty"` // payload contains a CapabilityRequest or CapabilityResponse Payload []byte `protobuf:"bytes,12,opt,name=payload,proto3" json:"payload,omitempty"` // Types that are assignable to Metadata: // // *MessageBody_TriggerRegistrationMetadata // *MessageBody_TriggerEventMetadata - Metadata isMessageBody_Metadata `protobuf_oneof:"metadata"` + Metadata isMessageBody_Metadata `protobuf_oneof:"metadata"` + CapabilityDonId uint32 `protobuf:"varint,15,opt,name=capability_don_id,json=capabilityDonId,proto3" json:"capability_don_id,omitempty"` + CallerDonId uint32 `protobuf:"varint,16,opt,name=caller_don_id,json=callerDonId,proto3" json:"caller_don_id,omitempty"` } func (x *MessageBody) Reset() { @@ -232,20 +232,6 @@ func (x *MessageBody) GetCapabilityId() string { return "" } -func (x *MessageBody) GetCapabilityDonId() string { - if x != nil { - return x.CapabilityDonId - } - return "" -} - -func (x *MessageBody) GetCallerDonId() string { - if x != nil { - return x.CallerDonId - } - return "" -} - func (x *MessageBody) GetMethod() string { if x != nil { return x.Method @@ -295,6 +281,20 @@ func (x *MessageBody) GetTriggerEventMetadata() *TriggerEventMetadata { return nil } +func (x *MessageBody) GetCapabilityDonId() uint32 { + if x != nil { + return x.CapabilityDonId + } + return 0 +} + +func (x *MessageBody) GetCallerDonId() uint32 { + if x != nil { + return x.CallerDonId + } + return 0 +} + type isMessageBody_Metadata interface { isMessageBody_Metadata() } @@ -494,7 +494,7 @@ var file_core_capabilities_remote_types_messages_proto_rawDesc = []byte{ 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x62, 0x6f, 0x64, 0x79, 0x22, 0xcd, 0x04, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x62, 0x6f, 0x64, 0x79, 0x22, 0xd9, 0x04, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, @@ -506,12 +506,7 @@ var file_core_capabilities_remote_types_messages_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x44, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x09, + 0x74, 0x79, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x23, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, @@ -530,44 +525,50 @@ var file_core_capabilities_remote_types_messages_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x14, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x22, 0x52, 0x0a, 0x1b, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x14, 0x54, 0x72, 0x69, 0x67, - 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x28, 0x0a, 0x10, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x69, 0x67, - 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, - 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x73, 0x22, 0xe3, 0x01, - 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, - 0x79, 0x4d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x12, - 0x38, 0x0a, 0x17, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, - 0x6f, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x17, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, 0x6f, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, - 0x79, 0x4d, 0x73, 0x2a, 0x76, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, - 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, - 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, - 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, - 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, - 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x20, 0x5a, 0x1e, 0x63, - 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, - 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x61, 0x70, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x64, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x61, 0x6c, + 0x6c, 0x65, 0x72, 0x44, 0x6f, 0x6e, 0x49, 0x64, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, + 0x22, 0x52, 0x0a, 0x1b, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x33, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, + 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x13, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x14, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x10, + 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x73, 0x22, 0xe3, 0x01, 0x0a, 0x13, 0x52, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x4d, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x12, 0x38, 0x0a, 0x17, 0x6d, + 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, 0x6f, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x6d, 0x69, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x54, 0x6f, 0x41, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x73, 0x2a, + 0x76, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, + 0x12, 0x15, 0x0a, 0x11, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x41, 0x50, 0x41, 0x42, + 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, + 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x51, + 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, + 0x54, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x20, 0x5a, 0x1e, 0x63, 0x6f, 0x72, 0x65, 0x2f, + 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/core/capabilities/remote/types/messages.proto b/core/capabilities/remote/types/messages.proto index a576e0e5fa1..4855892f9f4 100644 --- a/core/capabilities/remote/types/messages.proto +++ b/core/capabilities/remote/types/messages.proto @@ -19,14 +19,13 @@ message Message { } message MessageBody { + reserved 7, 8; uint32 version = 1; bytes sender = 2; bytes receiver = 3; int64 timestamp = 4; bytes message_id = 5; // scoped to sender string capability_id = 6; - string capability_don_id = 7; - string caller_don_id = 8; string method = 9; Error error = 10; string errorMsg = 11; @@ -38,6 +37,8 @@ message MessageBody { TriggerEventMetadata trigger_event_metadata = 14; } + uint32 capability_don_id = 15; + uint32 caller_don_id = 16; } message TriggerRegistrationMetadata { diff --git a/core/capabilities/remote/types/mocks/dispatcher.go b/core/capabilities/remote/types/mocks/dispatcher.go index 9ef7cee78d1..35905dbd0a2 100644 --- a/core/capabilities/remote/types/mocks/dispatcher.go +++ b/core/capabilities/remote/types/mocks/dispatcher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -14,7 +14,7 @@ type Dispatcher struct { } // RemoveReceiver provides a mock function with given fields: capabilityId, donId -func (_m *Dispatcher) RemoveReceiver(capabilityId string, donId string) { +func (_m *Dispatcher) RemoveReceiver(capabilityId string, donId uint32) { _m.Called(capabilityId, donId) } @@ -37,7 +37,7 @@ func (_m *Dispatcher) Send(peerID ragep2ptypes.PeerID, msgBody *types.MessageBod } // SetReceiver provides a mock function with given fields: capabilityId, donId, receiver -func (_m *Dispatcher) SetReceiver(capabilityId string, donId string, receiver types.Receiver) error { +func (_m *Dispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { ret := _m.Called(capabilityId, donId, receiver) if len(ret) == 0 { @@ -45,7 +45,7 @@ func (_m *Dispatcher) SetReceiver(capabilityId string, donId string, receiver ty } var r0 error - if rf, ok := ret.Get(0).(func(string, string, types.Receiver) error); ok { + if rf, ok := ret.Get(0).(func(string, uint32, types.Receiver) error); ok { r0 = rf(capabilityId, donId, receiver) } else { r0 = ret.Error(0) diff --git a/core/capabilities/remote/types/mocks/receiver.go b/core/capabilities/remote/types/mocks/receiver.go index b2329123537..701ab0f011f 100644 --- a/core/capabilities/remote/types/mocks/receiver.go +++ b/core/capabilities/remote/types/mocks/receiver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/remote/types/types.go b/core/capabilities/remote/types/types.go index 9c9cf67aa15..1f2527b6220 100644 --- a/core/capabilities/remote/types/types.go +++ b/core/capabilities/remote/types/types.go @@ -20,8 +20,8 @@ const ( //go:generate mockery --quiet --name Dispatcher --output ./mocks/ --case=underscore type Dispatcher interface { - SetReceiver(capabilityId string, donId string, receiver Receiver) error - RemoveReceiver(capabilityId string, donId string) + SetReceiver(capabilityId string, donId uint32, receiver Receiver) error + RemoveReceiver(capabilityId string, donId uint32) Send(peerID p2ptypes.PeerID, msgBody *MessageBody) error } diff --git a/core/capabilities/remote/utils_test.go b/core/capabilities/remote/utils_test.go index b5f97af99ed..8bebf71fb66 100644 --- a/core/capabilities/remote/utils_test.go +++ b/core/capabilities/remote/utils_test.go @@ -22,7 +22,7 @@ import ( const ( capId1 = "cap1" capId2 = "cap2" - donId1 = "donA" + donId1 = uint32(1) payload1 = "hello world" payload2 = "goodbye world" ) @@ -58,7 +58,7 @@ func newKeyPair(t *testing.T) (ed25519.PrivateKey, ragetypes.PeerID) { return privKey, peerID } -func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2ptypes.PeerID, receiverId p2ptypes.PeerID, capabilityId string, donId string, payload []byte) p2ptypes.Message { +func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2ptypes.PeerID, receiverId p2ptypes.PeerID, capabilityId string, donId uint32, payload []byte) p2ptypes.Message { body := remotetypes.MessageBody{ Sender: senderId[:], Receiver: receiverId[:], @@ -89,7 +89,7 @@ func TestToPeerID(t *testing.T) { } func TestDefaultModeAggregator_Aggregate(t *testing.T) { - val, err := values.Wrap(triggerEvent1) + val, err := values.NewMap(triggerEvent1) require.NoError(t, err) capResponse1 := commoncap.CapabilityResponse{ Value: val, @@ -98,7 +98,7 @@ func TestDefaultModeAggregator_Aggregate(t *testing.T) { marshaled1, err := pb.MarshalCapabilityResponse(capResponse1) require.NoError(t, err) - val2, err := values.Wrap(triggerEvent2) + val2, err := values.NewMap(triggerEvent2) require.NoError(t, err) capResponse2 := commoncap.CapabilityResponse{ Value: val2, diff --git a/core/capabilities/streams/codec.go b/core/capabilities/streams/codec.go index 21784cdcf40..d2bc451a39f 100644 --- a/core/capabilities/streams/codec.go +++ b/core/capabilities/streams/codec.go @@ -18,36 +18,12 @@ type codec struct { var _ datastreams.ReportCodec = &codec{} -func (c *codec) UnwrapValid(wrapped values.Value, allowedSigners [][]byte, minRequiredSignatures int) ([]datastreams.FeedReport, error) { - signersMap := make(map[common.Address]struct{}) - for _, signer := range allowedSigners { - signersMap[common.BytesToAddress(signer)] = struct{}{} - } - dest := []datastreams.FeedReport{} - err := wrapped.UnwrapTo(&dest) +func (c *codec) Unwrap(wrapped values.Value) ([]datastreams.FeedReport, error) { + dest, err := datastreams.UnwrapFeedReportList(wrapped) if err != nil { return nil, fmt.Errorf("failed to unwrap: %v", err) } for i, report := range dest { - // signatures (report and context are signed together) - sigData := append(crypto.Keccak256(report.FullReport), report.ReportContext...) - fullHash := crypto.Keccak256(sigData) - validated := map[common.Address]struct{}{} - for _, sig := range report.Signatures { - signerPubkey, err2 := crypto.SigToPub(fullHash, sig) - if err2 != nil { - return nil, fmt.Errorf("malformed signer: %v", err2) - } - signerAddr := crypto.PubkeyToAddress(*signerPubkey) - if _, ok := signersMap[signerAddr]; !ok { - c.lggr.Debugw("invalid signer", "signerAddr", signerAddr) - continue - } - validated[signerAddr] = struct{}{} - } - if len(validated) < minRequiredSignatures { - return nil, fmt.Errorf("not enough valid signatures %d, needed %d", len(validated), minRequiredSignatures) - } // decoding fields id, err2 := datastreams.NewFeedID(report.FeedID) if err2 != nil { @@ -68,6 +44,36 @@ func (c *codec) Wrap(reports []datastreams.FeedReport) (values.Value, error) { return values.Wrap(reports) } +func (c *codec) Validate(report datastreams.FeedReport, allowedSigners [][]byte, minRequiredSignatures int) error { + signersMap := make(map[common.Address]struct{}) + for _, signer := range allowedSigners { + signersMap[common.BytesToAddress(signer)] = struct{}{} + } + // signatures (report and context are signed together) + sigData := append(crypto.Keccak256(report.FullReport), report.ReportContext...) + fullHash := crypto.Keccak256(sigData) + validated := map[common.Address]struct{}{} + for _, sig := range report.Signatures { + signerPubkey, err2 := crypto.SigToPub(fullHash, sig) + if err2 != nil { + return fmt.Errorf("malformed signer: %v", err2) + } + signerAddr := crypto.PubkeyToAddress(*signerPubkey) + if _, ok := signersMap[signerAddr]; !ok { + c.lggr.Debugw("invalid signer", "signerAddr", signerAddr) + continue + } + validated[signerAddr] = struct{}{} + if len(validated) >= minRequiredSignatures { + break // early exit + } + } + if len(validated) < minRequiredSignatures { + return fmt.Errorf("not enough valid signatures %d, needed %d", len(validated), minRequiredSignatures) + } + return nil +} + func NewCodec(lggr logger.Logger) *codec { return &codec{lggr: lggr} } diff --git a/core/capabilities/streams/codec_test.go b/core/capabilities/streams/codec_test.go index 22100b0af52..e3ada731e43 100644 --- a/core/capabilities/streams/codec_test.go +++ b/core/capabilities/streams/codec_test.go @@ -66,21 +66,25 @@ func TestCodec_WrapUnwrap(t *testing.T) { require.NoError(t, err) // wrong type - _, err = codec.UnwrapValid(values.NewBool(true), nil, 0) + _, err = codec.Unwrap(values.NewBool(true)) require.Error(t, err) - // wrong signatures - _, err = codec.UnwrapValid(wrapped, nil, 1) - require.Error(t, err) - - // success - reports, err := codec.UnwrapValid(wrapped, allowedSigners, 2) + // correct reports byt wrong signatures + unwrapped, err := codec.Unwrap(wrapped) require.NoError(t, err) - require.Equal(t, 2, len(reports)) - require.Equal(t, price1.Bytes(), reports[0].BenchmarkPrice) - require.Equal(t, price2.Bytes(), reports[1].BenchmarkPrice) - require.Equal(t, timestamp1, reports[0].ObservationTimestamp) - require.Equal(t, timestamp2, reports[1].ObservationTimestamp) + require.Equal(t, 2, len(unwrapped)) + require.Equal(t, price1.Bytes(), unwrapped[0].BenchmarkPrice) + require.Equal(t, price2.Bytes(), unwrapped[1].BenchmarkPrice) + require.Equal(t, timestamp1, unwrapped[0].ObservationTimestamp) + require.Equal(t, timestamp2, unwrapped[1].ObservationTimestamp) + for _, report := range unwrapped { + require.Error(t, codec.Validate(report, nil, 1)) + } + + // valid signatures + for _, report := range unwrapped { + require.NoError(t, codec.Validate(report, allowedSigners, 2)) + } } func newFeedID(t *testing.T) ([32]byte, string) { diff --git a/core/capabilities/streams/consensus_agg_test.go b/core/capabilities/streams/consensus_agg_test.go new file mode 100644 index 00000000000..506ad26f86f --- /dev/null +++ b/core/capabilities/streams/consensus_agg_test.go @@ -0,0 +1,123 @@ +package streams_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/datafeeds" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/datastreams" + "github.com/smartcontractkit/chainlink-common/pkg/values" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +// Integration/load test that combines Data Feeds Consensus Aggregator and Streams Codec. +// For more meaningful measurements, increase the values of parameters P and T. +func TestStreamsConsensusAggregator(t *testing.T) { + Nt := 10 // trigger DON nodes + Ft := 3 // trigger DON faulty nodes + Nw := 10 // workflow DON nodes + Fw := 3 // workflow DON faulty nodes + P := 40 // feeds + T := 2 // test iterations + + triggerNodes := newNodes(t, Nt) + feeds := newFeedsWithSignedReports(t, triggerNodes, Nt, P, 1) + allowedSigners := make([][]byte, Nt) + for i := 0; i < Nt; i++ { + allowedSigners[i] = triggerNodes[i].bundle.PublicKey() // bad name - see comment on evmKeyring.PublicKey + } + + config := newAggConfig(t, feeds) + lggr := logger.TestLogger(t) + codec := streams.NewCodec(lggr) + agg, err := datafeeds.NewDataFeedsAggregator(*config, codec, lggr) + require.NoError(t, err) + + // init round - empty previous Outcome, empty observations + outcome, err := agg.Aggregate(nil, map[commontypes.OracleID][]values.Value{}, Fw) + require.NoError(t, err) + require.False(t, outcome.ShouldReport) + + // validate metadata + newState := &datafeeds.DataFeedsOutcomeMetadata{} + err = proto.Unmarshal(outcome.Metadata, newState) + require.NoError(t, err) + require.Equal(t, P, len(newState.FeedInfo)) + + // run test aggregations + startTs := time.Now().UnixMilli() + processingTime := int64(0) + for c := 0; c < T; c++ { + obs := newObservations(t, Nw, feeds, Ft+1, allowedSigners) + processingStart := time.Now().UnixMilli() + outcome, err = agg.Aggregate(outcome, obs, Fw) + processingTime += time.Now().UnixMilli() - processingStart + require.NoError(t, err) + } + totalTime := time.Now().UnixMilli() - startTs + lggr.Infow("elapsed", "totalMs", totalTime, "processingMs", processingTime) +} + +func newAggConfig(t *testing.T, feeds []feed) *values.Map { + feedMap := map[string]any{} + for _, feed := range feeds { + feedMap[feed.feedIDStr] = map[string]any{ + "deviation": "0.1", + "heartbeat": 1, + "remappedID": feed.feedIDStr, + } + } + unwrappedConfig := map[string]any{ + "feeds": feedMap, + "allowedPartialStaleness": "0.2", + } + config, err := values.NewMap(unwrappedConfig) + require.NoError(t, err) + return config +} + +func newObservations(t *testing.T, nNodes int, feeds []feed, minRequiredSignatures int, allowedSigners [][]byte) map[commontypes.OracleID][]values.Value { + observations := map[commontypes.OracleID][]values.Value{} + for i := 0; i < nNodes; i++ { + reportList := []datastreams.FeedReport{} + for j := 0; j < len(feeds); j++ { + reportIdx := 0 + signedStreamsReport := datastreams.FeedReport{ + FeedID: feeds[j].feedIDStr, + FullReport: feeds[j].reports[reportIdx].rawReport, + ReportContext: feeds[j].reports[reportIdx].reportCtx, + Signatures: feeds[j].reports[reportIdx].signatures, + } + reportList = append(reportList, signedStreamsReport) + } + + payloadVal, err := values.Wrap(reportList) + require.NoError(t, err) + + meta := datastreams.SignersMetadata{ + Signers: allowedSigners, + MinRequiredSignatures: minRequiredSignatures, + } + metaVal, err := values.Wrap(meta) + require.NoError(t, err) + + triggerEvent := capabilities.TriggerEvent{ + TriggerType: triggerID, + ID: "unused", + Timestamp: "1234", + Metadata: metaVal, + Payload: payloadVal, + } + wrappedEvent, err := values.Wrap(triggerEvent) + require.NoError(t, err) + observations[commontypes.OracleID(i)] = []values.Value{wrappedEvent} + } + return observations +} diff --git a/core/capabilities/streams/trigger_test.go b/core/capabilities/streams/trigger_test.go index b8106e9212e..6d8c9a27c1d 100644 --- a/core/capabilities/streams/trigger_test.go +++ b/core/capabilities/streams/trigger_test.go @@ -191,10 +191,13 @@ func newTriggerEvent(t *testing.T, reportList []datastreams.FeedReport, triggerE Payload: val, } - eventVal, err := values.Wrap(triggerEvent) + eventVal, err := values.WrapMap(triggerEvent) require.NoError(t, err) - marshaled, err := pb.MarshalCapabilityResponse(capabilities.CapabilityResponse{Value: eventVal}) + marshaled, err := pb.MarshalCapabilityResponse( + capabilities.CapabilityResponse{ + Value: eventVal, + }) require.NoError(t, err) msg := &remotetypes.MessageBody{ Sender: sender[:], diff --git a/core/capabilities/targets/mocks/chain_reader.go b/core/capabilities/targets/mocks/chain_reader.go index 14748c16bb8..6ad40c71597 100644 --- a/core/capabilities/targets/mocks/chain_reader.go +++ b/core/capabilities/targets/mocks/chain_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/targets/mocks/chain_writer.go b/core/capabilities/targets/mocks/chain_writer.go index 8fe9a0585f0..ef3613305b6 100644 --- a/core/capabilities/targets/mocks/chain_writer.go +++ b/core/capabilities/targets/mocks/chain_writer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/capabilities/transmission/local_target_capability.go b/core/capabilities/transmission/local_target_capability.go index c040e6ed432..1240d3a0e7f 100644 --- a/core/capabilities/transmission/local_target_capability.go +++ b/core/capabilities/transmission/local_target_capability.go @@ -14,19 +14,21 @@ import ( type LocalTargetCapability struct { lggr logger.Logger capabilities.TargetCapability - localNode capabilities.Node + localNode capabilities.Node + capabilityID string } -func NewLocalTargetCapability(lggr logger.Logger, localDON capabilities.Node, underlying capabilities.TargetCapability) *LocalTargetCapability { +func NewLocalTargetCapability(lggr logger.Logger, capabilityID string, localDON capabilities.Node, underlying capabilities.TargetCapability) *LocalTargetCapability { return &LocalTargetCapability{ TargetCapability: underlying, + capabilityID: capabilityID, lggr: lggr, localNode: localDON, } } func (l *LocalTargetCapability) Execute(ctx context.Context, req capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) { - if l.localNode.PeerID == nil || l.localNode.WorkflowDON.ID == "" { + if l.localNode.PeerID == nil || l.localNode.WorkflowDON.ID == 0 { l.lggr.Debugf("empty DON info, executing immediately") return l.TargetCapability.Execute(ctx, req) } @@ -38,7 +40,7 @@ func (l *LocalTargetCapability) Execute(ctx context.Context, req capabilities.Ca peerIDToTransmissionDelay, err := GetPeerIDToTransmissionDelay(l.localNode.WorkflowDON.Members, req) if err != nil { - return nil, fmt.Errorf("failed to get peer ID to transmission delay map: %w", err) + return nil, fmt.Errorf("capability id: %s failed to get peer ID to transmission delay map: %w", l.capabilityID, err) } delay, existsForPeerID := peerIDToTransmissionDelay[*l.localNode.PeerID] diff --git a/core/capabilities/transmission/local_target_capability_test.go b/core/capabilities/transmission/local_target_capability_test.go index ded4b5c30f1..93bf708ccef 100644 --- a/core/capabilities/transmission/local_target_capability_test.go +++ b/core/capabilities/transmission/local_target_capability_test.go @@ -134,12 +134,12 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) { } localDON := capabilities.Node{ WorkflowDON: capabilities.DON{ - ID: "1", + ID: 1, Members: ids, }, PeerID: &ids[tc.position], } - localTargetCapability := NewLocalTargetCapability(log, localDON, mt) + localTargetCapability := NewLocalTargetCapability(log, "capabilityID", localDON, mt) _, err = localTargetCapability.Execute(tests.Context(t), req) diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 8d1dcb6cc8c..f18c900b038 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -60,6 +60,9 @@ type Client interface { HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error) HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head, error) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) + // LatestFinalizedBlock - returns the latest finalized block as it's returned from an RPC. + // CAUTION: Using this method might cause local finality violations. It's highly recommended + // to use HeadTracker to get latest finalized block. LatestFinalizedBlock(ctx context.Context) (head *evmtypes.Head, err error) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) @@ -132,6 +135,7 @@ func NewChainClient( chainID *big.Int, chainType chaintype.ChainType, clientErrors evmconfig.ClientErrors, + deathDeclarationDelay time.Duration, ) Client { multiNode := commonclient.NewMultiNode( lggr, @@ -146,6 +150,7 @@ func NewChainClient( return ClassifySendError(err, clientErrors, logger.Sugared(logger.Nop()), tx, common.Address{}, chainType.IsL2()) }, 0, // use the default value provided by the implementation + deathDeclarationDelay, ) return &chainClient{ multiNode: multiNode, @@ -306,12 +311,7 @@ func (c *chainClient) SubscribeFilterLogs(ctx context.Context, q ethereum.Filter } func (c *chainClient) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) { - csf := newChainIDSubForwarder(c.ConfiguredChainID(), ch) - err := csf.start(c.multiNode.Subscribe(ctx, csf.srcCh, "newHeads")) - if err != nil { - return nil, err - } - return csf, nil + return c.multiNode.SubscribeNewHead(ctx, ch) } func (c *chainClient) SuggestGasPrice(ctx context.Context) (p *big.Int, err error) { diff --git a/core/chains/evm/client/chain_client_test.go b/core/chains/evm/client/chain_client_test.go index f18ec539677..33955c16451 100644 --- a/core/chains/evm/client/chain_client_test.go +++ b/core/chains/evm/client/chain_client_test.go @@ -751,7 +751,7 @@ func newMockRpc(t *testing.T) *mocks.RPCClient { mockRpc.On("Close").Return(nil).Once() mockRpc.On("ChainID", mock.Anything).Return(testutils.FixtureChainID, nil).Once() // node does not always manage to fully setup aliveLoop, so we have to make calls optional to avoid flakes - mockRpc.On("Subscribe", mock.Anything, mock.Anything, mock.Anything).Return(client.NewMockSubscription(), nil).Maybe() + mockRpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(client.NewMockSubscription(), nil).Maybe() mockRpc.On("SetAliveLoopSub", mock.Anything).Return().Maybe() return mockRpc } @@ -777,6 +777,7 @@ func TestChainClient_BatchCallContext(t *testing.T) { } mockRpc := newMockRpc(t) + mockRpc.On("GetInterceptedChainInfo").Return(commonclient.ChainInfo{}, commonclient.ChainInfo{}).Maybe() mockRpc.On("BatchCallContext", mock.Anything, b).Run(func(args mock.Arguments) { reqs := args.Get(1).([]rpc.BatchElem) for i := 0; i < len(reqs); i++ { diff --git a/core/chains/evm/client/chain_id_sub_test.go b/core/chains/evm/client/chain_id_sub_test.go deleted file mode 100644 index f959376acca..00000000000 --- a/core/chains/evm/client/chain_id_sub_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package client - -import ( - "errors" - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" -) - -func TestChainIDSubForwarder(t *testing.T) { - t.Parallel() - - chainID := big.NewInt(123) - - t.Run("unsubscribe forwarder", func(t *testing.T) { - t.Parallel() - - ch := make(chan *evmtypes.Head) - forwarder := newChainIDSubForwarder(chainID, ch) - sub := NewMockSubscription() - err := forwarder.start(sub, nil) - assert.NoError(t, err) - forwarder.Unsubscribe() - - assert.True(t, sub.unsubscribed) - _, ok := <-sub.Err() - assert.False(t, ok) - _, ok = <-forwarder.Err() - assert.False(t, ok) - }) - - t.Run("unsubscribe forwarder with error", func(t *testing.T) { - t.Parallel() - - ch := make(chan *evmtypes.Head) - forwarder := newChainIDSubForwarder(chainID, ch) - sub := NewMockSubscription() - err := forwarder.start(sub, nil) - assert.NoError(t, err) - sub.Errors <- errors.New("boo") - forwarder.Unsubscribe() - - assert.True(t, sub.unsubscribed) - _, ok := <-sub.Err() - assert.False(t, ok) - _, ok = <-forwarder.Err() - assert.False(t, ok) - }) - - t.Run("unsubscribe forwarder with message", func(t *testing.T) { - t.Parallel() - - ch := make(chan *evmtypes.Head) - forwarder := newChainIDSubForwarder(chainID, ch) - sub := NewMockSubscription() - err := forwarder.start(sub, nil) - assert.NoError(t, err) - forwarder.srcCh <- &evmtypes.Head{} - forwarder.Unsubscribe() - - assert.True(t, sub.unsubscribed) - _, ok := <-sub.Err() - assert.False(t, ok) - _, ok = <-forwarder.Err() - assert.False(t, ok) - }) - - t.Run("non nil error parameter", func(t *testing.T) { - t.Parallel() - - ch := make(chan *evmtypes.Head) - forwarder := newChainIDSubForwarder(chainID, ch) - sub := NewMockSubscription() - errIn := errors.New("foo") - errOut := forwarder.start(sub, errIn) - assert.Equal(t, errIn, errOut) - }) - - t.Run("forwarding", func(t *testing.T) { - t.Parallel() - - ch := make(chan *evmtypes.Head) - forwarder := newChainIDSubForwarder(chainID, ch) - sub := NewMockSubscription() - err := forwarder.start(sub, nil) - assert.NoError(t, err) - - head := &evmtypes.Head{ - ID: 1, - } - forwarder.srcCh <- head - receivedHead := <-ch - assert.Equal(t, head, receivedHead) - assert.Equal(t, ubig.New(chainID), receivedHead.EVMChainID) - - expectedErr := errors.New("error") - sub.Errors <- expectedErr - receivedErr := <-forwarder.Err() - assert.Equal(t, expectedErr, receivedErr) - }) -} diff --git a/core/chains/evm/client/config_builder.go b/core/chains/evm/client/config_builder.go index ae41d40dd33..19e0f14fd67 100644 --- a/core/chains/evm/client/config_builder.go +++ b/core/chains/evm/client/config_builder.go @@ -38,6 +38,9 @@ func NewClientConfigs( noNewHeadsThreshold time.Duration, finalityDepth *uint32, finalityTagEnabled *bool, + finalizedBlockOffset *uint32, + enforceRepeatableRead *bool, + deathDeclarationDelay time.Duration, ) (commonclient.ChainConfig, evmconfig.NodePool, []*toml.Node, error) { nodes, err := parseNodeConfigs(nodeCfgs) @@ -45,21 +48,24 @@ func NewClientConfigs( return nil, nil, nil, err } nodePool := toml.NodePool{ - SelectionMode: selectionMode, - LeaseDuration: commonconfig.MustNewDuration(leaseDuration), - PollFailureThreshold: pollFailureThreshold, - PollInterval: commonconfig.MustNewDuration(pollInterval), - SyncThreshold: syncThreshold, - NodeIsSyncingEnabled: nodeIsSyncingEnabled, + SelectionMode: selectionMode, + LeaseDuration: commonconfig.MustNewDuration(leaseDuration), + PollFailureThreshold: pollFailureThreshold, + PollInterval: commonconfig.MustNewDuration(pollInterval), + SyncThreshold: syncThreshold, + NodeIsSyncingEnabled: nodeIsSyncingEnabled, + EnforceRepeatableRead: enforceRepeatableRead, + DeathDeclarationDelay: commonconfig.MustNewDuration(deathDeclarationDelay), } nodePoolCfg := &evmconfig.NodePoolConfig{C: nodePool} chainConfig := &evmconfig.EVMConfig{ C: &toml.EVMConfig{ Chain: toml.Chain{ - ChainType: chaintype.NewChainTypeConfig(chainType), - FinalityDepth: finalityDepth, - FinalityTagEnabled: finalityTagEnabled, - NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold), + ChainType: chaintype.NewChainTypeConfig(chainType), + FinalityDepth: finalityDepth, + FinalityTagEnabled: finalityTagEnabled, + NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold), + FinalizedBlockOffset: finalizedBlockOffset, }, }, } diff --git a/core/chains/evm/client/config_builder_test.go b/core/chains/evm/client/config_builder_test.go index 0e24161b27b..7c08bf18c1d 100644 --- a/core/chains/evm/client/config_builder_test.go +++ b/core/chains/evm/client/config_builder_test.go @@ -23,6 +23,9 @@ func TestClientConfigBuilder(t *testing.T) { syncThreshold := ptr(uint32(5)) nodeIsSyncingEnabled := ptr(false) chainTypeStr := "" + finalizedBlockOffset := ptr[uint32](16) + enforceRepeatableRead := ptr(true) + deathDeclarationDelay := time.Second * 3 nodeConfigs := []client.NodeConfig{ { Name: ptr("foo"), @@ -34,7 +37,8 @@ func TestClientConfigBuilder(t *testing.T) { finalityTagEnabled := ptr(true) noNewHeadsThreshold := time.Second chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, - pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, finalityTagEnabled) + pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, + finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay) require.NoError(t, err) // Validate node pool configs @@ -44,6 +48,8 @@ func TestClientConfigBuilder(t *testing.T) { require.Equal(t, pollInterval, nodePool.PollInterval()) require.Equal(t, *syncThreshold, nodePool.SyncThreshold()) require.Equal(t, *nodeIsSyncingEnabled, nodePool.NodeIsSyncingEnabled()) + require.Equal(t, *enforceRepeatableRead, nodePool.EnforceRepeatableRead()) + require.Equal(t, deathDeclarationDelay, nodePool.DeathDeclarationDelay()) // Validate node configs require.Equal(t, *nodeConfigs[0].Name, *nodes[0].Name) @@ -54,6 +60,7 @@ func TestClientConfigBuilder(t *testing.T) { require.Equal(t, noNewHeadsThreshold, chainCfg.NodeNoNewHeadsThreshold()) require.Equal(t, *finalityDepth, chainCfg.FinalityDepth()) require.Equal(t, *finalityTagEnabled, chainCfg.FinalityTagEnabled()) + require.Equal(t, *finalizedBlockOffset, chainCfg.FinalizedBlockOffset()) // let combiler tell us, when we do not have sufficient data to create evm client _ = client.NewEvmClient(nodePool, chainCfg, nil, logger.Test(t), big.NewInt(10), nodes, chaintype.ChainType(chainTypeStr)) diff --git a/core/chains/evm/client/evm_client.go b/core/chains/evm/client/evm_client.go index 4d309440590..fd7fa5868a4 100644 --- a/core/chains/evm/client/evm_client.go +++ b/core/chains/evm/client/evm_client.go @@ -35,5 +35,5 @@ func NewEvmClient(cfg evmconfig.NodePool, chainCfg commonclient.ChainConfig, cli } return NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), chainCfg.NodeNoNewHeadsThreshold(), - primaries, sendonlys, chainID, chainType, clientErrors) + primaries, sendonlys, chainID, chainType, clientErrors, cfg.DeathDeclarationDelay()) } diff --git a/core/chains/evm/client/evm_client_test.go b/core/chains/evm/client/evm_client_test.go index 29113d4c3c9..9ad25f96025 100644 --- a/core/chains/evm/client/evm_client_test.go +++ b/core/chains/evm/client/evm_client_test.go @@ -24,6 +24,9 @@ func TestNewEvmClient(t *testing.T) { syncThreshold := ptr(uint32(5)) nodeIsSyncingEnabled := ptr(false) chainTypeStr := "" + finalizedBlockOffset := ptr[uint32](16) + enforceRepeatableRead := ptr(true) + deathDeclarationDelay := time.Second * 3 nodeConfigs := []client.NodeConfig{ { Name: ptr("foo"), @@ -34,7 +37,8 @@ func TestNewEvmClient(t *testing.T) { finalityDepth := ptr(uint32(10)) finalityTagEnabled := ptr(true) chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, - pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, finalityTagEnabled) + pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, + finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay) require.NoError(t, err) client := client.NewEvmClient(nodePool, chainCfg, nil, logger.Test(t), testutils.FixtureChainID, nodes, chaintype.ChainType(chainTypeStr)) diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 391d580c1f6..e1017a5564f 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -87,6 +87,8 @@ type TestNodePoolConfig struct { NodeIsSyncingEnabledVal bool NodeFinalizedBlockPollInterval time.Duration NodeErrors config.ClientErrors + EnforceRepeatableReadVal bool + NodeDeathDeclarationDelay time.Duration } func (tc TestNodePoolConfig) PollFailureThreshold() uint32 { return tc.NodePollFailureThreshold } @@ -109,6 +111,14 @@ func (tc TestNodePoolConfig) Errors() config.ClientErrors { return tc.NodeErrors } +func (tc TestNodePoolConfig) EnforceRepeatableRead() bool { + return tc.EnforceRepeatableReadVal +} + +func (tc TestNodePoolConfig) DeathDeclarationDelay() time.Duration { + return tc.NodeDeathDeclarationDelay +} + func NewChainClientWithTestNode( t *testing.T, nodeCfg commonclient.NodeConfig, @@ -150,7 +160,7 @@ func NewChainClientWithTestNode( var chainType chaintype.ChainType clientErrors := NewTestClientErrors() - c := NewChainClient(lggr, nodeCfg.SelectionMode(), leaseDuration, noNewHeadsThreshold, primaries, sendonlys, chainID, chainType, &clientErrors) + c := NewChainClient(lggr, nodeCfg.SelectionMode(), leaseDuration, noNewHeadsThreshold, primaries, sendonlys, chainID, chainType, &clientErrors, 0) t.Cleanup(c.Close) return c, nil } @@ -165,7 +175,7 @@ func NewChainClientWithEmptyNode( lggr := logger.Test(t) var chainType chaintype.ChainType - c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, nil, nil, chainID, chainType, nil) + c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, nil, nil, chainID, chainType, nil, 0) t.Cleanup(c.Close) return c } @@ -191,7 +201,7 @@ func NewChainClientWithMockedRpc( cfg, clientMocks.ChainConfig{NoNewHeadsThresholdVal: noNewHeadsThreshold}, lggr, *parsed, nil, "eth-primary-node-0", 1, chainID, 1, rpc, "EVM") primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]{n} clientErrors := NewTestClientErrors() - c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaries, nil, chainID, chainType, &clientErrors) + c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaries, nil, chainID, chainType, &clientErrors, 0) t.Cleanup(c.Close) return c } diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index 58d51526626..8a5b29cf4cb 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/client/mocks/rpc_client.go b/core/chains/evm/client/mocks/rpc_client.go index 980a215ccfe..e6cb07af2f2 100644 --- a/core/chains/evm/client/mocks/rpc_client.go +++ b/core/chains/evm/client/mocks/rpc_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -9,6 +9,8 @@ import ( common "github.com/ethereum/go-ethereum/common" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + commontypes "github.com/smartcontractkit/chainlink/v2/common/types" context "context" @@ -442,6 +444,34 @@ func (_m *RPCClient) FilterEvents(ctx context.Context, query ethereum.FilterQuer return r0, r1 } +// GetInterceptedChainInfo provides a mock function with given fields: +func (_m *RPCClient) GetInterceptedChainInfo() (commonclient.ChainInfo, commonclient.ChainInfo) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetInterceptedChainInfo") + } + + var r0 commonclient.ChainInfo + var r1 commonclient.ChainInfo + if rf, ok := ret.Get(0).(func() (commonclient.ChainInfo, commonclient.ChainInfo)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() commonclient.ChainInfo); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(commonclient.ChainInfo) + } + + if rf, ok := ret.Get(1).(func() commonclient.ChainInfo); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(commonclient.ChainInfo) + } + + return r0, r1 +} + // HeaderByHash provides a mock function with given fields: ctx, h func (_m *RPCClient) HeaderByHash(ctx context.Context, h common.Hash) (*coretypes.Header, error) { ret := _m.Called(ctx, h) @@ -805,32 +835,29 @@ func (_m *RPCClient) SimulateTransaction(ctx context.Context, tx *coretypes.Tran return r0 } -// 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) { - var _ca []interface{} - _ca = append(_ca, ctx, channel) - _ca = append(_ca, args...) - ret := _m.Called(_ca...) +// 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) { + ret := _m.Called(ctx, q, ch) if len(ret) == 0 { - panic("no return value specified for Subscribe") + panic("no return value specified for SubscribeFilterLogs") } - var r0 commontypes.Subscription + var r0 ethereum.Subscription var r1 error - if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Head, ...interface{}) (commontypes.Subscription, error)); ok { - return rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) (ethereum.Subscription, error)); ok { + return rf(ctx, q, ch) } - if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Head, ...interface{}) commontypes.Subscription); ok { - r0 = rf(ctx, channel, args...) + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) ethereum.Subscription); ok { + r0 = rf(ctx, q, ch) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(commontypes.Subscription) + r0 = ret.Get(0).(ethereum.Subscription) } } - if rf, ok := ret.Get(1).(func(context.Context, chan<- *types.Head, ...interface{}) error); ok { - r1 = rf(ctx, channel, args...) + if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) error); ok { + r1 = rf(ctx, q, ch) } else { r1 = ret.Error(1) } @@ -838,29 +865,29 @@ func (_m *RPCClient) Subscribe(ctx context.Context, channel chan<- *types.Head, return r0, r1 } -// 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) { - ret := _m.Called(ctx, q, ch) +// SubscribeNewHead provides a mock function with given fields: ctx, channel +func (_m *RPCClient) SubscribeNewHead(ctx context.Context, channel chan<- *types.Head) (commontypes.Subscription, error) { + ret := _m.Called(ctx, channel) if len(ret) == 0 { - panic("no return value specified for SubscribeFilterLogs") + panic("no return value specified for SubscribeNewHead") } - var r0 ethereum.Subscription + var r0 commontypes.Subscription var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) (ethereum.Subscription, error)); ok { - return rf(ctx, q, ch) + if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Head) (commontypes.Subscription, error)); ok { + return rf(ctx, channel) } - if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) ethereum.Subscription); ok { - r0 = rf(ctx, q, ch) + if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Head) commontypes.Subscription); ok { + r0 = rf(ctx, channel) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(ethereum.Subscription) + r0 = ret.Get(0).(commontypes.Subscription) } } - if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery, chan<- coretypes.Log) error); ok { - r1 = rf(ctx, q, ch) + if rf, ok := ret.Get(1).(func(context.Context, chan<- *types.Head) error); ok { + r1 = rf(ctx, channel) } else { r1 = ret.Error(1) } diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 5b64900a0cb..6499b18f795 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -101,6 +101,7 @@ type RPCClient interface { SuggestGasPrice(ctx context.Context) (p *big.Int, err error) SuggestGasTipCap(ctx context.Context) (t *big.Int, err error) TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error) + GetInterceptedChainInfo() (latest, highestUserObservations commonclient.ChainInfo) } type rawclient struct { @@ -132,6 +133,11 @@ type rpcClient struct { // this rpcClient. Closing and replacing should be serialized through // stateMu since it can happen on state transitions as well as rpcClient Close. chStopInFlight chan struct{} + + // intercepted values seen by callers of the rpcClient excluding health check calls. Need to ensure MultiNode provides repeatable read guarantee + highestUserObservations commonclient.ChainInfo + // most recent chain info observed during current lifecycle (reseted on DisconnectAll) + latestChainInfo commonclient.ChainInfo } // NewRPCCLient returns a new *rpcClient as commonclient.RPC @@ -289,21 +295,32 @@ func (r *rpcClient) getRPCDomain() string { } // registerSub adds the sub to the rpcClient list -func (r *rpcClient) registerSub(sub ethereum.Subscription) { +func (r *rpcClient) registerSub(sub ethereum.Subscription, stopInFLightCh chan struct{}) error { r.stateMu.Lock() defer r.stateMu.Unlock() + // ensure that the `sub` belongs to current life cycle of the `rpcClient` and it should not be killed due to + // previous `DisconnectAll` call. + select { + case <-stopInFLightCh: + sub.Unsubscribe() + return fmt.Errorf("failed to register subscription - all in-flight requests were canceled") + default: + } + // TODO: BCI-3358 - delete sub when caller unsubscribes. r.subs = append(r.subs, sub) + return nil } -// disconnectAll disconnects all clients connected to the rpcClient -// WARNING: NOT THREAD-SAFE -// This must be called from within the r.stateMu lock +// DisconnectAll disconnects all clients connected to the rpcClient func (r *rpcClient) DisconnectAll() { + r.stateMu.Lock() + defer r.stateMu.Unlock() if r.ws.rpc != nil { r.ws.rpc.Close() } r.cancelInflightRequests() r.unsubscribeAll() + r.latestChainInfo = commonclient.ChainInfo{} } // unsubscribeAll unsubscribes all subscriptions @@ -388,24 +405,35 @@ func (r *rpcClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) err return err } -func (r *rpcClient) Subscribe(ctx context.Context, channel chan<- *evmtypes.Head, args ...interface{}) (commontypes.Subscription, error) { - ctx, cancel, ws, _ := r.makeLiveQueryCtxAndSafeGetClients(ctx) +func (r *rpcClient) SubscribeNewHead(ctx context.Context, channel chan<- *evmtypes.Head) (_ commontypes.Subscription, err error) { + ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx) defer cancel() + args := []interface{}{"newHeads"} lggr := r.newRqLggr().With("args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() - var sub commontypes.Subscription - sub, err := ws.rpc.EthSubscribe(ctx, channel, args...) - if err == nil { - sub = newSubscriptionErrorWrapper(sub, r.rpcClientErrorPrefix()) - r.registerSub(sub) + defer func() { + duration := time.Since(start) + r.logResult(lggr, err, duration, r.getRPCDomain(), "EthSubscribe") + err = r.wrapWS(err) + }() + subForwarder := newSubForwarder(channel, func(head *evmtypes.Head) *evmtypes.Head { + head.EVMChainID = ubig.New(r.chainID) + r.onNewHead(ctx, chStopInFlight, head) + return head + }, r.wrapRPCClientError) + err = subForwarder.start(ws.rpc.EthSubscribe(ctx, subForwarder.srcCh, args...)) + if err != nil { + return } - duration := time.Since(start) - r.logResult(lggr, err, duration, r.getRPCDomain(), "EthSubscribe") + err = r.registerSub(subForwarder, chStopInFlight) + if err != nil { + return + } - return sub, r.wrapWS(err) + return subForwarder, nil } // GethClient wrappers @@ -513,7 +541,7 @@ func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header return } -func (r *rpcClient) LatestFinalizedBlock(ctx context.Context) (head *evmtypes.Head, err error) { +func (r *rpcClient) LatestFinalizedBlock(ctx context.Context) (*evmtypes.Head, error) { return r.blockByNumber(ctx, rpc.FinalizedBlockNumber.String()) } @@ -523,7 +551,25 @@ func (r *rpcClient) BlockByNumber(ctx context.Context, number *big.Int) (head *e } func (r *rpcClient) blockByNumber(ctx context.Context, number string) (head *evmtypes.Head, err error) { - err = r.CallContext(ctx, &head, "eth_getBlockByNumber", number, false) + ctx, cancel, chStopInFlight, ws, http := r.acquireQueryCtx(ctx) + defer cancel() + const method = "eth_getBlockByNumber" + args := []interface{}{number, false} + lggr := r.newRqLggr().With( + "method", method, + "args", args, + ) + + lggr.Debug("RPC call: evmclient.Client#CallContext") + start := time.Now() + if http != nil { + err = r.wrapHTTP(http.rpc.CallContext(ctx, &head, method, args...)) + } else { + err = r.wrapWS(ws.rpc.CallContext(ctx, &head, method, args...)) + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "CallContext") if err != nil { return nil, err } @@ -532,6 +578,14 @@ func (r *rpcClient) blockByNumber(ctx context.Context, number string) (head *evm return } head.EVMChainID = ubig.New(r.chainID) + + switch number { + case rpc.FinalizedBlockNumber.String(): + r.onNewFinalizedHead(ctx, chStopInFlight, head) + case rpc.LatestBlockNumber.String(): + r.onNewHead(ctx, chStopInFlight, head) + } + return } @@ -958,24 +1012,30 @@ func (r *rpcClient) ClientVersion(ctx context.Context) (version string, err erro return } -func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (sub ethereum.Subscription, err error) { - ctx, cancel, ws, _ := r.makeLiveQueryCtxAndSafeGetClients(ctx) +func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (_ ethereum.Subscription, err error) { + ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx) defer cancel() lggr := r.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() - sub, err = ws.geth.SubscribeFilterLogs(ctx, q, ch) - if err == nil { - sub = newSubscriptionErrorWrapper(sub, r.rpcClientErrorPrefix()) - r.registerSub(sub) + defer func() { + duration := time.Since(start) + r.logResult(lggr, err, duration, r.getRPCDomain(), "SubscribeFilterLogs") + err = r.wrapWS(err) + }() + sub := newSubForwarder(ch, nil, r.wrapRPCClientError) + err = sub.start(ws.geth.SubscribeFilterLogs(ctx, q, sub.srcCh)) + if err != nil { + return } - err = r.wrapWS(err) - duration := time.Since(start) - r.logResult(lggr, err, duration, r.getRPCDomain(), "SubscribeFilterLogs") + err = r.registerSub(sub, chStopInFlight) + if err != nil { + return + } - return + return sub, nil } func (r *rpcClient) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err error) { @@ -1060,17 +1120,23 @@ func (r *rpcClient) wrapHTTP(err error) error { // makeLiveQueryCtxAndSafeGetClients wraps makeQueryCtx func (r *rpcClient) makeLiveQueryCtxAndSafeGetClients(parentCtx context.Context) (ctx context.Context, cancel context.CancelFunc, ws rawclient, http *rawclient) { + ctx, cancel, _, ws, http = r.acquireQueryCtx(parentCtx) + return +} + +func (r *rpcClient) acquireQueryCtx(parentCtx context.Context) (ctx context.Context, cancel context.CancelFunc, + chStopInFlight chan struct{}, ws rawclient, http *rawclient) { // Need to wrap in mutex because state transition can cancel and replace the // context r.stateMu.RLock() - cancelCh := r.chStopInFlight + chStopInFlight = r.chStopInFlight ws = r.ws if r.http != nil { cp := *r.http http = &cp } r.stateMu.RUnlock() - ctx, cancel = makeQueryCtx(parentCtx, cancelCh) + ctx, cancel = makeQueryCtx(parentCtx, chStopInFlight) return } @@ -1134,6 +1200,49 @@ func Name(r *rpcClient) string { return r.name } +func (r *rpcClient) onNewHead(ctx context.Context, requestCh <-chan struct{}, head *evmtypes.Head) { + if head == nil { + return + } + + r.stateMu.Lock() + defer r.stateMu.Unlock() + if !commonclient.CtxIsHeathCheckRequest(ctx) { + r.highestUserObservations.BlockNumber = max(r.highestUserObservations.BlockNumber, head.Number) + r.highestUserObservations.TotalDifficulty = commonclient.MaxTotalDifficulty(r.highestUserObservations.TotalDifficulty, head.TotalDifficulty) + } + select { + case <-requestCh: // no need to update latestChainInfo, as rpcClient already started new life cycle + return + default: + r.latestChainInfo.BlockNumber = head.Number + r.latestChainInfo.TotalDifficulty = head.TotalDifficulty + } +} + +func (r *rpcClient) onNewFinalizedHead(ctx context.Context, requestCh <-chan struct{}, head *evmtypes.Head) { + if head == nil { + return + } + r.stateMu.Lock() + defer r.stateMu.Unlock() + if !commonclient.CtxIsHeathCheckRequest(ctx) { + r.highestUserObservations.FinalizedBlockNumber = max(r.highestUserObservations.FinalizedBlockNumber, head.Number) + } + select { + case <-requestCh: // no need to update latestChainInfo, as rpcClient already started new life cycle + return + default: + r.latestChainInfo.FinalizedBlockNumber = head.Number + } +} + +func (r *rpcClient) GetInterceptedChainInfo() (latest, highestUserObservations commonclient.ChainInfo) { + r.stateMu.RLock() + defer r.stateMu.RUnlock() + return r.latestChainInfo, r.highestUserObservations +} + func ToBlockNumArg(number *big.Int) string { if number == nil { return "latest" diff --git a/core/chains/evm/client/rpc_client_test.go b/core/chains/evm/client/rpc_client_test.go new file mode 100644 index 00000000000..682c4352457 --- /dev/null +++ b/core/chains/evm/client/rpc_client_test.go @@ -0,0 +1,300 @@ +package client_test + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "net/url" + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + "go.uber.org/zap" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/testutils" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" +) + +func makeNewHeadWSMessage(head *evmtypes.Head) string { + asJSON, err := json.Marshal(head) + if err != nil { + panic(fmt.Errorf("failed to marshal head: %w", err)) + } + return fmt.Sprintf(`{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x00","result":%s}}`, string(asJSON)) +} + +func TestRPCClient_SubscribeNewHead(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithTimeout(tests.Context(t), tests.WaitTimeout(t)) + defer cancel() + + chainId := big.NewInt(123456) + lggr := logger.Test(t) + + serverCallBack := func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + if method == "eth_unsubscribe" { + resp.Result = "true" + return + } + assert.Equal(t, "eth_subscribe", method) + if assert.True(t, params.IsArray()) && assert.Equal(t, "newHeads", params.Array()[0].String()) { + resp.Result = `"0x00"` + } + return + } + t.Run("Updates chain info on new blocks", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, serverCallBack) + wsURL := server.WSURL() + + rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + defer rpc.Close() + require.NoError(t, rpc.Dial(ctx)) + // set to default values + latest, highestUserObservations := rpc.GetInterceptedChainInfo() + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(0), latest.FinalizedBlockNumber) + assert.Nil(t, latest.TotalDifficulty) + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(0), highestUserObservations.FinalizedBlockNumber) + assert.Nil(t, highestUserObservations.TotalDifficulty) + + ch := make(chan *evmtypes.Head) + sub, err := rpc.SubscribeNewHead(tests.Context(t), ch) + require.NoError(t, err) + defer sub.Unsubscribe() + go server.MustWriteBinaryMessageSync(t, makeNewHeadWSMessage(&evmtypes.Head{Number: 256, TotalDifficulty: big.NewInt(1000)})) + // received 256 head + <-ch + go server.MustWriteBinaryMessageSync(t, makeNewHeadWSMessage(&evmtypes.Head{Number: 128, TotalDifficulty: big.NewInt(500)})) + // received 128 head + <-ch + + latest, highestUserObservations = rpc.GetInterceptedChainInfo() + assert.Equal(t, int64(128), latest.BlockNumber) + assert.Equal(t, int64(0), latest.FinalizedBlockNumber) + assert.Equal(t, big.NewInt(500), latest.TotalDifficulty) + + assertHighestUserObservations := func(highestUserObservations commonclient.ChainInfo) { + assert.Equal(t, int64(256), highestUserObservations.BlockNumber) + assert.Equal(t, int64(0), highestUserObservations.FinalizedBlockNumber) + assert.Equal(t, big.NewInt(1000), highestUserObservations.TotalDifficulty) + } + + assertHighestUserObservations(highestUserObservations) + + // DisconnectAll resets latest + rpc.DisconnectAll() + + latest, highestUserObservations = rpc.GetInterceptedChainInfo() + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(0), latest.FinalizedBlockNumber) + assert.Nil(t, latest.TotalDifficulty) + + assertHighestUserObservations(highestUserObservations) + }) + t.Run("App layer observations are not affected by new block if health check flag is present", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, serverCallBack) + wsURL := server.WSURL() + + rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + defer rpc.Close() + require.NoError(t, rpc.Dial(ctx)) + ch := make(chan *evmtypes.Head) + sub, err := rpc.SubscribeNewHead(commonclient.CtxAddHealthCheckFlag(tests.Context(t)), ch) + require.NoError(t, err) + defer sub.Unsubscribe() + go server.MustWriteBinaryMessageSync(t, makeNewHeadWSMessage(&evmtypes.Head{Number: 256, TotalDifficulty: big.NewInt(1000)})) + // received 256 head + <-ch + + latest, highestUserObservations := rpc.GetInterceptedChainInfo() + assert.Equal(t, int64(256), latest.BlockNumber) + assert.Equal(t, int64(0), latest.FinalizedBlockNumber) + assert.Equal(t, big.NewInt(1000), latest.TotalDifficulty) + + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(0), highestUserObservations.FinalizedBlockNumber) + assert.Equal(t, (*big.Int)(nil), highestUserObservations.TotalDifficulty) + }) + t.Run("Block's chain ID matched configured", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, serverCallBack) + wsURL := server.WSURL() + rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + defer rpc.Close() + require.NoError(t, rpc.Dial(ctx)) + ch := make(chan *evmtypes.Head) + sub, err := rpc.SubscribeNewHead(tests.Context(t), ch) + require.NoError(t, err) + defer sub.Unsubscribe() + go server.MustWriteBinaryMessageSync(t, makeNewHeadWSMessage(&evmtypes.Head{Number: 256})) + head := <-ch + require.Equal(t, chainId, head.ChainID()) + }) + t.Run("Failed SubscribeNewHead returns and logs proper error", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, func(reqMethod string, reqParams gjson.Result) (resp testutils.JSONRPCResponse) { + return resp + }) + wsURL := server.WSURL() + observedLggr, observed := logger.TestObserved(t, zap.DebugLevel) + rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + require.NoError(t, rpc.Dial(ctx)) + server.Close() + _, err := rpc.SubscribeNewHead(ctx, make(chan *evmtypes.Head)) + require.ErrorContains(t, err, "RPCClient returned error (rpc)") + tests.AssertLogEventually(t, observed, "evmclient.Client#EthSubscribe RPC call failure") + }) + t.Run("Subscription error is properly wrapper", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, serverCallBack) + wsURL := server.WSURL() + rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + defer rpc.Close() + require.NoError(t, rpc.Dial(ctx)) + sub, err := rpc.SubscribeNewHead(ctx, make(chan *evmtypes.Head)) + require.NoError(t, err) + go server.MustWriteBinaryMessageSync(t, "invalid msg") + select { + case err = <-sub.Err(): + require.ErrorContains(t, err, "RPCClient returned error (rpc): invalid character") + case <-ctx.Done(): + t.Errorf("Expected subscription to return an error, but test timeout instead") + } + }) +} + +func TestRPCClient_SubscribeFilterLogs(t *testing.T) { + t.Parallel() + + chainId := big.NewInt(123456) + lggr := logger.Test(t) + ctx, cancel := context.WithTimeout(tests.Context(t), tests.WaitTimeout(t)) + defer cancel() + t.Run("Failed SubscribeFilterLogs logs and returns proper error", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, func(reqMethod string, reqParams gjson.Result) (resp testutils.JSONRPCResponse) { + return resp + }) + wsURL := server.WSURL() + observedLggr, observed := logger.TestObserved(t, zap.DebugLevel) + rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + require.NoError(t, rpc.Dial(ctx)) + server.Close() + _, err := rpc.SubscribeFilterLogs(ctx, ethereum.FilterQuery{}, make(chan types.Log)) + require.ErrorContains(t, err, "RPCClient returned error (rpc)") + tests.AssertLogEventually(t, observed, "evmclient.Client#SubscribeFilterLogs RPC call failure") + }) + t.Run("Subscription error is properly wrapper", func(t *testing.T) { + server := testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + assert.Equal(t, "eth_subscribe", method) + if assert.True(t, params.IsArray()) && assert.Equal(t, "logs", params.Array()[0].String()) { + resp.Result = `"0x00"` + resp.Notify = "{}" + } + return resp + }) + wsURL := server.WSURL() + rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary) + defer rpc.Close() + require.NoError(t, rpc.Dial(ctx)) + sub, err := rpc.SubscribeFilterLogs(ctx, ethereum.FilterQuery{}, make(chan types.Log)) + require.NoError(t, err) + go server.MustWriteBinaryMessageSync(t, "invalid msg") + errorCtx, cancel := context.WithTimeout(ctx, tests.DefaultWaitTimeout) + defer cancel() + select { + case err = <-sub.Err(): + require.ErrorContains(t, err, "RPCClient returned error (rpc): invalid character") + case <-errorCtx.Done(): + t.Errorf("Expected subscription to return an error, but test timeout instead") + } + }) +} + +func TestRPCClient_LatestFinalizedBlock(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithTimeout(tests.Context(t), tests.WaitTimeout(t)) + defer cancel() + + chainId := big.NewInt(123456) + lggr := logger.Test(t) + + type rpcServer struct { + Head *evmtypes.Head + URL *url.URL + } + createRPCServer := func() *rpcServer { + server := &rpcServer{} + server.URL = testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + assert.Equal(t, "eth_getBlockByNumber", method) + if assert.True(t, params.IsArray()) && assert.Equal(t, "finalized", params.Array()[0].String()) { + head := server.Head + jsonHead, err := json.Marshal(head) + if err != nil { + panic(fmt.Errorf("failed to marshal head: %w", err)) + } + resp.Result = string(jsonHead) + } + + return + }).WSURL() + + return server + } + + server := createRPCServer() + rpc := client.NewRPCClient(lggr, *server.URL, nil, "rpc", 1, chainId, commonclient.Primary) + require.NoError(t, rpc.Dial(ctx)) + defer rpc.Close() + server.Head = &evmtypes.Head{Number: 128} + // updates chain info + _, err := rpc.LatestFinalizedBlock(ctx) + require.NoError(t, err) + latest, highestUserObservations := rpc.GetInterceptedChainInfo() + + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(128), highestUserObservations.FinalizedBlockNumber) + + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(128), latest.FinalizedBlockNumber) + + // lower block number does not update highestUserObservations + server.Head = &evmtypes.Head{Number: 127} + _, err = rpc.LatestFinalizedBlock(ctx) + require.NoError(t, err) + latest, highestUserObservations = rpc.GetInterceptedChainInfo() + + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(128), highestUserObservations.FinalizedBlockNumber) + + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(127), latest.FinalizedBlockNumber) + + // health check flg prevents change in highestUserObservations + server.Head = &evmtypes.Head{Number: 256} + _, err = rpc.LatestFinalizedBlock(commonclient.CtxAddHealthCheckFlag(ctx)) + require.NoError(t, err) + latest, highestUserObservations = rpc.GetInterceptedChainInfo() + + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(128), highestUserObservations.FinalizedBlockNumber) + + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(256), latest.FinalizedBlockNumber) + + // DisconnectAll resets latest ChainInfo + rpc.DisconnectAll() + latest, highestUserObservations = rpc.GetInterceptedChainInfo() + assert.Equal(t, int64(0), highestUserObservations.BlockNumber) + assert.Equal(t, int64(128), highestUserObservations.FinalizedBlockNumber) + + assert.Equal(t, int64(0), latest.BlockNumber) + assert.Equal(t, int64(0), latest.FinalizedBlockNumber) +} diff --git a/core/chains/evm/client/sub_error_wrapper.go b/core/chains/evm/client/sub_error_wrapper.go deleted file mode 100644 index 689991ce70f..00000000000 --- a/core/chains/evm/client/sub_error_wrapper.go +++ /dev/null @@ -1,77 +0,0 @@ -package client - -import ( - "fmt" - - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" -) - -// subErrorWrapper - adds specified prefix to a subscription error -type subErrorWrapper struct { - sub commontypes.Subscription - errorPrefix string - - done chan struct{} - unSub chan struct{} - errorCh chan error -} - -func newSubscriptionErrorWrapper(sub commontypes.Subscription, errorPrefix string) *subErrorWrapper { - s := &subErrorWrapper{ - sub: sub, - errorPrefix: errorPrefix, - done: make(chan struct{}), - unSub: make(chan struct{}), - errorCh: make(chan error), - } - - go func() { - for { - select { - // sub.Err channel is closed by sub.Unsubscribe - case err, ok := <-sub.Err(): - if !ok { - // might only happen if someone terminated wrapped subscription - // in any case - do our best to release resources - // we can't call Unsubscribe on root sub as this might cause panic - close(s.errorCh) - close(s.done) - return - } - - select { - case s.errorCh <- fmt.Errorf("%s: %w", s.errorPrefix, err): - case <-s.unSub: - s.close() - return - } - case <-s.unSub: - s.close() - return - } - } - }() - - return s -} - -func (s *subErrorWrapper) close() { - s.sub.Unsubscribe() - close(s.errorCh) - close(s.done) -} - -func (s *subErrorWrapper) Unsubscribe() { - select { - // already unsubscribed - case <-s.done: - // signal unsubscribe - case s.unSub <- struct{}{}: - // wait for unsubscribe to complete - <-s.done - } -} - -func (s *subErrorWrapper) Err() <-chan error { - return s.errorCh -} diff --git a/core/chains/evm/client/sub_error_wrapper_test.go b/core/chains/evm/client/sub_error_wrapper_test.go deleted file mode 100644 index 5dd81069572..00000000000 --- a/core/chains/evm/client/sub_error_wrapper_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package client - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" -) - -func TestSubscriptionErrorWrapper(t *testing.T) { - t.Parallel() - t.Run("Unsubscribe wrapper releases resources", func(t *testing.T) { - t.Parallel() - - mockedSub := NewMockSubscription() - const prefix = "RPC returned error" - wrapper := newSubscriptionErrorWrapper(mockedSub, prefix) - wrapper.Unsubscribe() - - // mock's resources were relased - assert.True(t, mockedSub.unsubscribed) - _, ok := <-mockedSub.Err() - assert.False(t, ok) - // wrapper's channels are closed - _, ok = <-wrapper.Err() - assert.False(t, ok) - // subsequence unsubscribe does not causes panic - wrapper.Unsubscribe() - }) - t.Run("Unsubscribe interrupts error delivery", func(t *testing.T) { - t.Parallel() - sub := NewMockSubscription() - const prefix = "RPC returned error" - wrapper := newSubscriptionErrorWrapper(sub, prefix) - sub.Errors <- fmt.Errorf("error") - - wrapper.Unsubscribe() - _, ok := <-wrapper.Err() - assert.False(t, ok) - }) - t.Run("Successfully wraps error", func(t *testing.T) { - t.Parallel() - sub := NewMockSubscription() - const prefix = "RPC returned error" - wrapper := newSubscriptionErrorWrapper(sub, prefix) - sub.Errors <- fmt.Errorf("root error") - - err, ok := <-wrapper.Err() - assert.True(t, ok) - assert.Equal(t, "RPC returned error: root error", err.Error()) - - wrapper.Unsubscribe() - _, ok = <-wrapper.Err() - assert.False(t, ok) - }) - t.Run("Unsubscribe on root does not cause panic", func(t *testing.T) { - t.Parallel() - mockedSub := NewMockSubscription() - wrapper := newSubscriptionErrorWrapper(mockedSub, "") - - mockedSub.Unsubscribe() - // mock's resources were released - assert.True(t, mockedSub.unsubscribed) - _, ok := <-mockedSub.Err() - assert.False(t, ok) - // wrapper's channels are eventually closed - tests.AssertEventually(t, func() bool { - _, ok = <-wrapper.Err() - return !ok - }) - }) -} diff --git a/core/chains/evm/client/chain_id_sub.go b/core/chains/evm/client/sub_forwarder.go similarity index 51% rename from core/chains/evm/client/chain_id_sub.go rename to core/chains/evm/client/sub_forwarder.go index c3162b300c7..93e9b106b4a 100644 --- a/core/chains/evm/client/chain_id_sub.go +++ b/core/chains/evm/client/sub_forwarder.go @@ -1,42 +1,40 @@ package client import ( - "math/big" - "github.com/ethereum/go-ethereum" - - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) -var _ ethereum.Subscription = &chainIDSubForwarder{} +var _ ethereum.Subscription = &subForwarder[any]{} -// chainIDSubForwarder wraps a head subscription in order to intercept and augment each head with chainID before forwarding. -type chainIDSubForwarder struct { - chainID *big.Int - destCh chan<- *evmtypes.Head +// subForwarder wraps a subscription in order to intercept and augment each result before forwarding. +type subForwarder[T any] struct { + destCh chan<- T - srcCh chan *evmtypes.Head + srcCh chan T srcSub ethereum.Subscription + interceptResult func(T) T + interceptError func(error) error + done chan struct{} err chan error unSub chan struct{} } -func newChainIDSubForwarder(chainID *big.Int, ch chan<- *evmtypes.Head) *chainIDSubForwarder { - return &chainIDSubForwarder{ - chainID: chainID, - destCh: ch, - srcCh: make(chan *evmtypes.Head), - done: make(chan struct{}), - err: make(chan error), - unSub: make(chan struct{}, 1), +func newSubForwarder[T any](destCh chan<- T, interceptResult func(T) T, interceptError func(error) error) *subForwarder[T] { + return &subForwarder[T]{ + interceptResult: interceptResult, + interceptError: interceptError, + destCh: destCh, + srcCh: make(chan T), + done: make(chan struct{}), + err: make(chan error), + unSub: make(chan struct{}, 1), } } // start spawns the forwarding loop for sub. -func (c *chainIDSubForwarder) start(sub ethereum.Subscription, err error) error { +func (c *subForwarder[T]) start(sub ethereum.Subscription, err error) error { if err != nil { close(c.srcCh) return err @@ -48,7 +46,7 @@ func (c *chainIDSubForwarder) start(sub ethereum.Subscription, err error) error // forwardLoop receives from src, adds the chainID, and then sends to dest. // It also handles Unsubscribing, which may interrupt either forwarding operation. -func (c *chainIDSubForwarder) forwardLoop() { +func (c *subForwarder[T]) forwardLoop() { // the error channel must be closed when unsubscribing defer close(c.err) defer close(c.done) @@ -56,6 +54,9 @@ func (c *chainIDSubForwarder) forwardLoop() { for { select { case err := <-c.srcSub.Err(): + if c.interceptError != nil { + err = c.interceptError(err) + } select { case c.err <- err: case <-c.unSub: @@ -64,7 +65,9 @@ func (c *chainIDSubForwarder) forwardLoop() { return case h := <-c.srcCh: - h.EVMChainID = ubig.New(c.chainID) + if c.interceptResult != nil { + h = c.interceptResult(h) + } select { case c.destCh <- h: case <-c.unSub: @@ -79,7 +82,7 @@ func (c *chainIDSubForwarder) forwardLoop() { } } -func (c *chainIDSubForwarder) Unsubscribe() { +func (c *subForwarder[T]) Unsubscribe() { // tell forwardLoop to unsubscribe select { case c.unSub <- struct{}{}: @@ -90,6 +93,6 @@ func (c *chainIDSubForwarder) Unsubscribe() { <-c.done } -func (c *chainIDSubForwarder) Err() <-chan error { +func (c *subForwarder[T]) Err() <-chan error { return c.err } diff --git a/core/chains/evm/client/sub_forwarder_test.go b/core/chains/evm/client/sub_forwarder_test.go new file mode 100644 index 00000000000..1bc0122603b --- /dev/null +++ b/core/chains/evm/client/sub_forwarder_test.go @@ -0,0 +1,190 @@ +package client + +import ( + "errors" + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" +) + +func TestChainIDSubForwarder(t *testing.T) { + t.Parallel() + + newChainIDSubForwarder := func(chainID *big.Int, ch chan<- *evmtypes.Head) *subForwarder[*evmtypes.Head] { + return newSubForwarder(ch, func(head *evmtypes.Head) *evmtypes.Head { + head.EVMChainID = ubig.New(chainID) + return head + }, nil) + } + + chainID := big.NewInt(123) + + t.Run("unsubscribe forwarder", func(t *testing.T) { + t.Parallel() + + ch := make(chan *evmtypes.Head) + forwarder := newChainIDSubForwarder(chainID, ch) + sub := NewMockSubscription() + err := forwarder.start(sub, nil) + assert.NoError(t, err) + forwarder.Unsubscribe() + + assert.True(t, sub.unsubscribed) + _, ok := <-sub.Err() + assert.False(t, ok) + _, ok = <-forwarder.Err() + assert.False(t, ok) + }) + + t.Run("unsubscribe forwarder with error", func(t *testing.T) { + t.Parallel() + + ch := make(chan *evmtypes.Head) + forwarder := newChainIDSubForwarder(chainID, ch) + sub := NewMockSubscription() + err := forwarder.start(sub, nil) + assert.NoError(t, err) + sub.Errors <- errors.New("boo") + forwarder.Unsubscribe() + + assert.True(t, sub.unsubscribed) + _, ok := <-sub.Err() + assert.False(t, ok) + _, ok = <-forwarder.Err() + assert.False(t, ok) + }) + + t.Run("unsubscribe forwarder with message", func(t *testing.T) { + t.Parallel() + + ch := make(chan *evmtypes.Head) + forwarder := newChainIDSubForwarder(chainID, ch) + sub := NewMockSubscription() + err := forwarder.start(sub, nil) + assert.NoError(t, err) + forwarder.srcCh <- &evmtypes.Head{} + forwarder.Unsubscribe() + + assert.True(t, sub.unsubscribed) + _, ok := <-sub.Err() + assert.False(t, ok) + _, ok = <-forwarder.Err() + assert.False(t, ok) + }) + + t.Run("non nil error parameter", func(t *testing.T) { + t.Parallel() + + ch := make(chan *evmtypes.Head) + forwarder := newChainIDSubForwarder(chainID, ch) + sub := NewMockSubscription() + errIn := errors.New("foo") + errOut := forwarder.start(sub, errIn) + assert.Equal(t, errIn, errOut) + }) + + t.Run("forwarding", func(t *testing.T) { + t.Parallel() + + ch := make(chan *evmtypes.Head) + forwarder := newChainIDSubForwarder(chainID, ch) + sub := NewMockSubscription() + err := forwarder.start(sub, nil) + assert.NoError(t, err) + + head := &evmtypes.Head{ + ID: 1, + } + forwarder.srcCh <- head + receivedHead := <-ch + assert.Equal(t, head, receivedHead) + assert.Equal(t, ubig.New(chainID), receivedHead.EVMChainID) + + expectedErr := errors.New("error") + sub.Errors <- expectedErr + receivedErr := <-forwarder.Err() + assert.Equal(t, expectedErr, receivedErr) + }) +} + +func TestSubscriptionErrorWrapper(t *testing.T) { + t.Parallel() + newSubscriptionErrorWrapper := func(t *testing.T, sub commontypes.Subscription, errorPrefix string) ethereum.Subscription { + ch := make(chan *evmtypes.Head) + result := newSubForwarder(ch, nil, func(err error) error { + return fmt.Errorf("%s: %w", errorPrefix, err) + }) + require.NoError(t, result.start(sub, nil)) + return result + } + t.Run("Unsubscribe wrapper releases resources", func(t *testing.T) { + t.Parallel() + + mockedSub := NewMockSubscription() + const prefix = "RPC returned error" + wrapper := newSubscriptionErrorWrapper(t, mockedSub, prefix) + wrapper.Unsubscribe() + + // mock's resources were released + assert.True(t, mockedSub.unsubscribed) + _, ok := <-mockedSub.Err() + assert.False(t, ok) + // wrapper's channels are closed + _, ok = <-wrapper.Err() + assert.False(t, ok) + // subsequence unsubscribe does not causes panic + wrapper.Unsubscribe() + }) + t.Run("Unsubscribe interrupts error delivery", func(t *testing.T) { + t.Parallel() + sub := NewMockSubscription() + const prefix = "RPC returned error" + wrapper := newSubscriptionErrorWrapper(t, sub, prefix) + sub.Errors <- fmt.Errorf("error") + + wrapper.Unsubscribe() + _, ok := <-wrapper.Err() + assert.False(t, ok) + }) + t.Run("Successfully wraps error", func(t *testing.T) { + t.Parallel() + sub := NewMockSubscription() + const prefix = "RPC returned error" + wrapper := newSubscriptionErrorWrapper(t, sub, prefix) + sub.Errors <- fmt.Errorf("root error") + + err, ok := <-wrapper.Err() + assert.True(t, ok) + assert.Equal(t, "RPC returned error: root error", err.Error()) + + wrapper.Unsubscribe() + _, ok = <-wrapper.Err() + assert.False(t, ok) + }) + t.Run("Unsubscribe on root does not cause panic", func(t *testing.T) { + t.Parallel() + mockedSub := NewMockSubscription() + wrapper := newSubscriptionErrorWrapper(t, mockedSub, "") + + mockedSub.Unsubscribe() + // mock's resources were released + assert.True(t, mockedSub.unsubscribed) + _, ok := <-mockedSub.Err() + assert.False(t, ok) + // wrapper's channels are eventually closed + tests.AssertEventually(t, func() bool { + _, ok = <-wrapper.Err() + return !ok + }) + }) +} diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index 8064e2de207..db598e3e82b 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -179,3 +179,7 @@ func (e *EVMConfig) OperatorFactoryAddress() string { func (e *EVMConfig) LogPrunePageSize() uint32 { return *e.C.LogPrunePageSize } + +func (e *EVMConfig) FinalizedBlockOffset() uint32 { + return *e.C.FinalizedBlockOffset +} diff --git a/core/chains/evm/config/chain_scoped_node_pool.go b/core/chains/evm/config/chain_scoped_node_pool.go index 50269366829..a4974366486 100644 --- a/core/chains/evm/config/chain_scoped_node_pool.go +++ b/core/chains/evm/config/chain_scoped_node_pool.go @@ -38,6 +38,12 @@ func (n *NodePoolConfig) FinalizedBlockPollInterval() time.Duration { return n.C.FinalizedBlockPollInterval.Duration() } -func (n *NodePoolConfig) Errors() ClientErrors { - return &clientErrorsConfig{c: n.C.Errors} +func (n *NodePoolConfig) Errors() ClientErrors { return &clientErrorsConfig{c: n.C.Errors} } + +func (n *NodePoolConfig) EnforceRepeatableRead() bool { + return *n.C.EnforceRepeatableRead +} + +func (n *NodePoolConfig) DeathDeclarationDelay() time.Duration { + return n.C.DeathDeclarationDelay.Duration() } diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index b44c112e204..ffb2a496baf 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -45,6 +45,7 @@ type EVM interface { OperatorFactoryAddress() string RPCDefaultBatchSize() uint32 NodeNoNewHeadsThreshold() time.Duration + FinalizedBlockOffset() uint32 IsEnabled() bool TOMLString() (string, error) @@ -170,6 +171,8 @@ type NodePool interface { NodeIsSyncingEnabled() bool FinalizedBlockPollInterval() time.Duration Errors() ClientErrors + EnforceRepeatableRead() bool + DeathDeclarationDelay() time.Duration } // 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 26ac2db0852..ba362bda981 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -326,6 +326,8 @@ func TestNodePoolConfig(t *testing.T) { 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()) + require.Equal(t, false, cfg.EVM().NodePool().EnforceRepeatableRead()) + require.Equal(t, time.Duration(10000000000), cfg.EVM().NodePool().DeathDeclarationDelay()) } func TestClientErrorsConfig(t *testing.T) { diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index 7f5f9666ae6..730c6c61c4e 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index 549f16fe558..9ad7420977d 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index d35f9bd0a3b..3e35bb4b55c 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -358,6 +358,7 @@ type Chain struct { OperatorFactoryAddress *types.EIP55Address RPCDefaultBatchSize *uint32 RPCBlockQueryDelay *uint16 + FinalizedBlockOffset *uint32 Transactions Transactions `toml:",omitempty"` BalanceMonitor BalanceMonitor `toml:",omitempty"` @@ -389,6 +390,11 @@ func (c *Chain) ValidateConfig() (err error) { Msg: "must be greater than or equal to 1"}) } + if *c.FinalizedBlockOffset > *c.HeadTracker.HistoryDepth { + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "HeadTracker.HistoryDepth", Value: *c.HeadTracker.HistoryDepth, + Msg: "must be greater than or equal to FinalizedBlockOffset"}) + } + // AutoPurge configs depend on ChainType so handling validation on per chain basis if c.Transactions.AutoPurge.Enabled != nil && *c.Transactions.AutoPurge.Enabled { chainType := c.ChainType.ChainType() @@ -842,6 +848,8 @@ type NodePool struct { NodeIsSyncingEnabled *bool FinalizedBlockPollInterval *commonconfig.Duration Errors ClientErrors `toml:",omitempty"` + EnforceRepeatableRead *bool + DeathDeclarationDelay *commonconfig.Duration } func (p *NodePool) setFrom(f *NodePool) { @@ -866,6 +874,14 @@ func (p *NodePool) setFrom(f *NodePool) { if v := f.FinalizedBlockPollInterval; v != nil { p.FinalizedBlockPollInterval = v } + + if v := f.EnforceRepeatableRead; v != nil { + p.EnforceRepeatableRead = v + } + + if v := f.DeathDeclarationDelay; v != nil { + p.DeathDeclarationDelay = v + } p.Errors.setFrom(&f.Errors) } diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index e006babfb68..38eef40bf76 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -161,6 +161,9 @@ func (c *Chain) SetFrom(f *Chain) { if v := f.RPCBlockQueryDelay; v != nil { c.RPCBlockQueryDelay = v } + if v := f.FinalizedBlockOffset; v != nil { + c.FinalizedBlockOffset = v + } c.Transactions.setFrom(&f.Transactions) c.BalanceMonitor.setFrom(&f.BalanceMonitor) diff --git a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml index 47895e6a6d5..4a887b504df 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml @@ -1,20 +1,22 @@ ChainID = '534352' FinalityDepth = 10 +FinalityTagEnabled = true ChainType = 'scroll' -LogPollInterval = '3s' +LogPollInterval = '5s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful NoNewHeadsThreshold = '0' -OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'SuggestedPrice' -# Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price -PriceMin = '0' +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '1 gwei' [GasEstimator.BlockHistory] -# Force an error if someone enables the estimator by accident; we never want to run the block history estimator on Scroll -BlockHistorySize = 0 +BlockHistorySize = 24 [HeadTracker] HistoryDepth = 50 + +[OCR] +ContractConfirmations = 1 diff --git a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml index d2626a86bd4..b2e1cfbd733 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml @@ -1,20 +1,22 @@ ChainID = '534351' FinalityDepth = 10 +FinalityTagEnabled = true ChainType = 'scroll' -LogPollInterval = '3s' +LogPollInterval = '5s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful NoNewHeadsThreshold = '0' -OCR.ContractConfirmations = 1 [GasEstimator] -Mode = 'SuggestedPrice' -# Scroll uses the SuggestedPrice estimator; we don't want to place any limits on the minimum gas price -PriceMin = '0' +EIP1559DynamicFees = true +PriceMin = '1 wei' +BumpMin = '1 gwei' [GasEstimator.BlockHistory] -# Force an error if someone enables the estimator by accident; we never want to run the block history estimator on Scroll -BlockHistorySize = 0 +BlockHistorySize = 24 [HeadTracker] HistoryDepth = 50 + +[OCR] +ContractConfirmations = 1 diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml index 5a16aca091c..a11e646e08b 100644 --- a/core/chains/evm/config/toml/defaults/fallback.toml +++ b/core/chains/evm/config/toml/defaults/fallback.toml @@ -14,6 +14,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -68,6 +69,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 3624cdf7a2b..6436988ba82 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -16,8 +16,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -276,10 +274,12 @@ func (f *FwdMgr) runLoop() { ctx, cancel := f.stopCh.NewCtx() defer cancel() - tick := time.After(0) - for ; ; tick = time.After(utils.WithJitter(time.Minute)) { + ticker := services.NewTicker(time.Minute) + defer ticker.Stop() + + for { select { - case <-tick: + case <-ticker.C: if err := f.logpoller.Ready(); err != nil { f.logger.Warnw("Skipping log syncing", "err", err) continue diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index 7489f4028f4..55f69f134b2 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -75,7 +76,8 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(evmClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, ht, lpOpts) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM()) fwdMgr.ORM = forwarders.NewORM(db) @@ -136,7 +138,8 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(evmClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, ht, lpOpts) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM()) fwdMgr.ORM = forwarders.NewORM(db) @@ -201,7 +204,8 @@ func TestFwdMgr_InvalidForwarderForOCR2FeedsStates(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(evmClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), evmClient, lggr, ht, lpOpts) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM()) fwdMgr.ORM = forwarders.NewORM(db) diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index 04e252fa7d4..7cffdf171ce 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index 0cd4bbcdd0b..6a11932878b 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -11,8 +11,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups" @@ -168,27 +166,31 @@ func (a *arbitrumEstimator) getPricesInArbGas() (perL2Tx uint32, perL1CalldataUn func (a *arbitrumEstimator) run() { defer close(a.chDone) - t := a.refreshPricesInArbGas() + a.refreshPricesInArbGas() close(a.chInitialised) + t := services.TickerConfig{ + Initial: a.pollPeriod, + JitterPct: services.DefaultJitter, + }.NewTicker(a.pollPeriod) + defer t.Stop() + for { select { case <-a.chStop: return case ch := <-a.chForceRefetch: - t.Stop() - t = a.refreshPricesInArbGas() + a.refreshPricesInArbGas() + t.Reset() close(ch) case <-t.C: - t = a.refreshPricesInArbGas() + a.refreshPricesInArbGas() } } } // refreshPricesInArbGas calls getPricesInArbGas() and caches the refreshed prices. -func (a *arbitrumEstimator) refreshPricesInArbGas() (t *time.Timer) { - t = time.NewTimer(utils.WithJitter(a.pollPeriod)) - +func (a *arbitrumEstimator) refreshPricesInArbGas() { perL2Tx, perL1CalldataUnit, err := a.l1Oracle.GetPricesInArbGas() if err != nil { a.logger.Warnw("Failed to refresh prices", "err", err) @@ -201,5 +203,4 @@ func (a *arbitrumEstimator) refreshPricesInArbGas() (t *time.Timer) { a.perL2Tx = perL2Tx a.perL1CalldataUnit = perL1CalldataUnit a.getPricesInArbGasMu.Unlock() - return } diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 289025fcdab..cbc6d5d37f4 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -55,10 +55,11 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("calling GetLegacyGas on unstarted estimator returns error", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) - _, _, err := o.GetLegacyGas(tests.Context(t), calldata, gasLimit, maxGasPrice) + _, _, err = o.GetLegacyGas(tests.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "estimator is not started") }) @@ -68,7 +69,8 @@ func TestArbitrumEstimator(t *testing.T) { zeros.Write(common.BigToHash(big.NewInt(123455)).Bytes()) t.Run("calling GetLegacyGas on started estimator returns estimates", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -93,7 +95,8 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("gas price is lower than user specified max gas price", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) @@ -119,7 +122,8 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("gas price is lower than global max gas price", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) @@ -144,16 +148,18 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("calling BumpLegacyGas on unstarted arbitrum estimator returns error", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) - _, _, err := o.BumpLegacyGas(tests.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) + _, _, err = o.BumpLegacyGas(tests.Context(t), assets.NewWeiI(42), gasLimit, assets.NewWeiI(10), nil) assert.EqualError(t, err, "estimator is not started") }) t.Run("calling GetLegacyGas on started estimator if initial call failed returns error", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) @@ -168,35 +174,38 @@ func TestArbitrumEstimator(t *testing.T) { servicetest.RunHealthy(t, o) - _, _, err := o.GetLegacyGas(tests.Context(t), calldata, gasLimit, maxGasPrice) + _, _, err = o.GetLegacyGas(tests.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "failed to estimate gas; gas price not set") }) t.Run("calling GetDynamicFee always returns error", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) - _, err := o.GetDynamicFee(tests.Context(t), maxGasPrice) + _, err = o.GetDynamicFee(tests.Context(t), maxGasPrice) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) t.Run("calling BumpDynamicFee always returns error", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, feeEstimatorClient, l1Oracle) fee := gas.DynamicFee{ FeeCap: assets.NewWeiI(42), TipCap: assets.NewWeiI(5), } - _, err := o.BumpDynamicFee(tests.Context(t), fee, maxGasPrice, nil) + _, err = o.BumpDynamicFee(tests.Context(t), fee, maxGasPrice, nil) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) t.Run("limit computes", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) @@ -232,7 +241,8 @@ func TestArbitrumEstimator(t *testing.T) { t.Run("limit exceeds max", func(t *testing.T) { feeEstimatorClient := mocks.NewFeeEstimatorClient(t) - l1Oracle := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + l1Oracle, err := rollups.NewArbitrumL1GasOracle(logger.Test(t), feeEstimatorClient) + require.NoError(t, err) feeEstimatorClient.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(nil).Run(func(args mock.Arguments) { res := args.Get(1).(*hexutil.Big) diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index 714d82aa8c6..c2f4a2219cb 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -1506,6 +1506,15 @@ func TestBlockHistoryEstimator_IsUsable(t *testing.T) { cfg.ChainTypeF = "" assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) }) + + t.Run("returns false if transaction is of type 0x7e only on Scroll", func(t *testing.T) { + cfg.ChainTypeF = string(chaintype.ChainScroll) + tx := evmtypes.Transaction{Type: 0x7e, GasPrice: assets.NewWeiI(10), GasLimit: 42, Hash: utils.NewHash()} + assert.Equal(t, false, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) + + cfg.ChainTypeF = "" + assert.Equal(t, true, bhe.IsUsable(tx, block, cfg.ChainType(), geCfg.PriceMin(), logger.Test(t))) + }) } func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { diff --git a/core/chains/evm/gas/chain_specific.go b/core/chains/evm/gas/chain_specific.go index fba2eda66a0..4be7d1972f8 100644 --- a/core/chains/evm/gas/chain_specific.go +++ b/core/chains/evm/gas/chain_specific.go @@ -19,7 +19,7 @@ func chainSpecificIsUsable(tx evmtypes.Transaction, baseFee *assets.Wei, chainTy return false } } - if chainType == chaintype.ChainOptimismBedrock || chainType == chaintype.ChainKroma { + if chainType == chaintype.ChainOptimismBedrock || chainType == chaintype.ChainKroma || chainType == chaintype.ChainScroll { // This is a special deposit transaction type introduced in Bedrock upgrade. // This is a system transaction that it will occur at least one time per block. // We should discard this type before even processing it to avoid flooding the diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index 5daac211762..b4a5e40f2f7 100644 --- a/core/chains/evm/gas/mocks/config.go +++ b/core/chains/evm/gas/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index 1213a71742d..8c8693413f1 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index 5179a2560d0..73821335617 100644 --- a/core/chains/evm/gas/mocks/evm_fee_estimator.go +++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/mocks/fee_estimator_client.go b/core/chains/evm/gas/mocks/fee_estimator_client.go index d81120e2ed4..d375b478a70 100644 --- a/core/chains/evm/gas/mocks/fee_estimator_client.go +++ b/core/chains/evm/gas/mocks/fee_estimator_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 320834cabab..8c1d19280ae 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -52,7 +52,7 @@ type feeEstimatorClient interface { } // NewEstimator returns the estimator for a given config -func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config, geCfg evmconfig.GasEstimator) EvmFeeEstimator { +func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config, geCfg evmconfig.GasEstimator) (EvmFeeEstimator, error) { bh := geCfg.BlockHistory() s := geCfg.Mode() lggr.Infow(fmt.Sprintf("Initializing EVM gas estimator in mode: %s", s), @@ -79,13 +79,21 @@ func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config, // create l1Oracle only if it is supported for the chain var l1Oracle rollups.L1Oracle if rollups.IsRollupWithL1Support(cfg.ChainType()) { - l1Oracle = rollups.NewL1GasOracle(lggr, ethClient, cfg.ChainType()) + var err error + l1Oracle, err = rollups.NewL1GasOracle(lggr, ethClient, cfg.ChainType()) + if err != nil { + return nil, fmt.Errorf("failed to initialize L1 oracle: %w", err) + } } var newEstimator func(logger.Logger) EvmEstimator switch s { case "Arbitrum": + arbOracle, err := rollups.NewArbitrumL1GasOracle(lggr, ethClient) + if err != nil { + return nil, fmt.Errorf("failed to initialize Arbitrum L1 oracle: %w", err) + } newEstimator = func(l logger.Logger) EvmEstimator { - return NewArbitrumEstimator(lggr, geCfg, ethClient, rollups.NewArbitrumL1GasOracle(lggr, ethClient)) + return NewArbitrumEstimator(lggr, geCfg, ethClient, arbOracle) } case "BlockHistory": newEstimator = func(l logger.Logger) EvmEstimator { @@ -105,7 +113,7 @@ func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config, return NewFixedPriceEstimator(geCfg, ethClient, bh, lggr, l1Oracle) } } - return NewEvmFeeEstimator(lggr, newEstimator, df, geCfg) + return NewEvmFeeEstimator(lggr, newEstimator, df, geCfg), nil } // DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index 059d0ed3d05..92ea901596f 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -65,7 +65,8 @@ func TestWrappedEvmEstimator(t *testing.T) { assert.Nil(t, l1Oracle) // expect l1Oracle - oracle := rollups.NewL1GasOracle(lggr, nil, chaintype.ChainOptimismBedrock) + oracle, err := rollups.NewL1GasOracle(lggr, nil, chaintype.ChainOptimismBedrock) + require.NoError(t, err) // cast oracle to L1Oracle interface estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg) diff --git a/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go b/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go index 9e15cfe4c93..c01244db70c 100644 --- a/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go +++ b/core/chains/evm/gas/rollups/arbitrum_l1_oracle.go @@ -13,11 +13,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - - gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -71,7 +70,7 @@ const ( ArbGasInfo_getPricesInArbGas = "02199f34" ) -func NewArbitrumL1GasOracle(lggr logger.Logger, ethClient l1OracleClient) *arbitrumL1Oracle { +func NewArbitrumL1GasOracle(lggr logger.Logger, ethClient l1OracleClient) (*arbitrumL1Oracle, error) { var l1GasPriceAddress, gasPriceMethod, l1GasCostAddress, gasCostMethod string var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI var gasPriceErr, gasCostErr error @@ -84,10 +83,10 @@ func NewArbitrumL1GasOracle(lggr logger.Logger, ethClient l1OracleClient) *arbit l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GasEstimateL1ComponentAbiString)) if gasPriceErr != nil { - panic("Failed to parse L1 gas price method ABI for chain: arbitrum") + return nil, fmt.Errorf("failed to parse L1 gas price method ABI for chain: arbitrum: %w", gasPriceErr) } if gasCostErr != nil { - panic("Failed to parse L1 gas cost method ABI for chain: arbitrum") + return nil, fmt.Errorf("failed to parse L1 gas cost method ABI for chain: arbitrum: %w", gasCostErr) } return &arbitrumL1Oracle{ @@ -106,7 +105,7 @@ func NewArbitrumL1GasOracle(lggr logger.Logger, ethClient l1OracleClient) *arbit chInitialised: make(chan struct{}), chStop: make(chan struct{}), chDone: make(chan struct{}), - } + }, nil } func (o *arbitrumL1Oracle) Name() string { @@ -135,41 +134,45 @@ func (o *arbitrumL1Oracle) HealthReport() map[string]error { func (o *arbitrumL1Oracle) run() { defer close(o.chDone) - t := o.refresh() + o.refresh() close(o.chInitialised) + t := services.TickerConfig{ + Initial: o.pollPeriod, + JitterPct: services.DefaultJitter, + }.NewTicker(o.pollPeriod) + defer t.Stop() + for { select { case <-o.chStop: return case <-t.C: - t = o.refresh() + o.refresh() } } } -func (o *arbitrumL1Oracle) refresh() (t *time.Timer) { - t, err := o.refreshWithError() +func (o *arbitrumL1Oracle) refresh() { + err := o.refreshWithError() if err != nil { + o.logger.Criticalw("Failed to refresh gas price", "err", err) o.SvcErrBuffer.Append(err) } - return } -func (o *arbitrumL1Oracle) refreshWithError() (t *time.Timer, err error) { - t = time.NewTimer(utils.WithJitter(o.pollPeriod)) - +func (o *arbitrumL1Oracle) refreshWithError() error { ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) defer cancel() price, err := o.fetchL1GasPrice(ctx) if err != nil { - return t, err + return err } o.l1GasPriceMu.Lock() defer o.l1GasPriceMu.Unlock() o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} - return + return nil } func (o *arbitrumL1Oracle) fetchL1GasPrice(ctx context.Context) (price *big.Int, err error) { diff --git a/core/chains/evm/gas/rollups/l1_oracle.go b/core/chains/evm/gas/rollups/l1_oracle.go index 97cc673154b..234ddd9fdc9 100644 --- a/core/chains/evm/gas/rollups/l1_oracle.go +++ b/core/chains/evm/gas/rollups/l1_oracle.go @@ -52,20 +52,24 @@ func IsRollupWithL1Support(chainType chaintype.ChainType) bool { return slices.Contains(supportedChainTypes, chainType) } -func NewL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType) L1Oracle { +func NewL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType) (L1Oracle, error) { if !IsRollupWithL1Support(chainType) { - return nil + return nil, nil } var l1Oracle L1Oracle + var err error switch chainType { case chaintype.ChainOptimismBedrock, chaintype.ChainKroma, chaintype.ChainScroll: - l1Oracle = NewOpStackL1GasOracle(lggr, ethClient, chainType) + l1Oracle, err = NewOpStackL1GasOracle(lggr, ethClient, chainType) case chaintype.ChainArbitrum: - l1Oracle = NewArbitrumL1GasOracle(lggr, ethClient) + l1Oracle, err = NewArbitrumL1GasOracle(lggr, ethClient) case chaintype.ChainZkSync: l1Oracle = NewZkSyncL1GasOracle(lggr, ethClient) default: - panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) + return nil, fmt.Errorf("received unsupported chaintype %s", chainType) } - return l1Oracle + if err != nil { + return nil, fmt.Errorf("failed to initialize L1 oracle for chaintype %s: %w", chainType, err) + } + return l1Oracle, nil } diff --git a/core/chains/evm/gas/rollups/l1_oracle_abi.go b/core/chains/evm/gas/rollups/l1_oracle_abi.go index dc18e43c98e..fa5d9c85391 100644 --- a/core/chains/evm/gas/rollups/l1_oracle_abi.go +++ b/core/chains/evm/gas/rollups/l1_oracle_abi.go @@ -12,6 +12,10 @@ const GasEstimateL1ComponentAbiString = `[{"inputs":[{"internalType":"address"," const L1BaseFeeAbiString = `[{"inputs":[],"name":"l1BaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` const GetL1FeeAbiString = `[{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getL1Fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` -// ABIs for OP Stack Ecotone GasPriceOracle methods needed to calculated encoded gas price +// ABIs for OP Stack GasPriceOracle methods needed to calculated encoded gas price const OPIsEcotoneAbiString = `[{"inputs":[],"name":"isEcotone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]` -const OPGetL1GasUsedAbiString = `[{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getL1GasUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` +const OPIsFjordAbiString = `[{"inputs":[],"name":"isFjord","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]` +const OPBaseFeeScalarAbiString = `[{"inputs":[],"name":"baseFeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]` +const OPBlobBaseFeeAbiString = `[{"inputs":[],"name":"blobBaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` +const OPBlobBaseFeeScalarAbiString = `[{"inputs":[],"name":"blobBaseFeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]` +const OPDecimalsAbiString = `[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]` diff --git a/core/chains/evm/gas/rollups/l1_oracle_test.go b/core/chains/evm/gas/rollups/l1_oracle_test.go index 800a3558d12..7a28523d396 100644 --- a/core/chains/evm/gas/rollups/l1_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_oracle_test.go @@ -2,7 +2,6 @@ package rollups import ( "encoding/hex" - "errors" "math/big" "strings" "testing" @@ -31,7 +30,9 @@ func TestL1Oracle(t *testing.T) { t.Run("Unsupported ChainType returns nil", func(t *testing.T) { ethClient := mocks.NewL1OracleClient(t) - assert.Nil(t, NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainCelo)) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainCelo) + require.NoError(t, err) + assert.Nil(t, oracle) }) } @@ -41,9 +42,10 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Run("Calling GasPrice on unstarted L1Oracle returns error", func(t *testing.T) { ethClient := mocks.NewL1OracleClient(t) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock) + require.NoError(t, err) - _, err := oracle.GasPrice(tests.Context(t)) + _, err = oracle.GasPrice(tests.Context(t)) assert.EqualError(t, err, "L1GasOracle is not started; cannot estimate gas") }) @@ -63,7 +65,8 @@ func TestL1Oracle_GasPrice(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainArbitrum) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainArbitrum) + require.NoError(t, err) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(tests.Context(t)) @@ -78,19 +81,7 @@ func TestL1Oracle_GasPrice(t *testing.T) { l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) require.NoError(t, err) - isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) - require.NoError(t, err) - - ethClient := mocks.NewL1OracleClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - var payload []byte - payload, err = isEcotoneAbiString.Pack("isEcotone") - require.NoError(t, err) - require.Equal(t, payload, callMsg.Data) - assert.Nil(t, blockNumber) - }).Return(nil, errors.New("not ecotone")).Once() + ethClient := setupUpgradeCheck(t, KromaGasOracleAddress, false, false) // Ecotone, Fjord disabled ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) @@ -102,7 +93,8 @@ func TestL1Oracle_GasPrice(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainKroma, KromaGasOracleAddress) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainKroma) + require.NoError(t, err) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(tests.Context(t)) @@ -117,19 +109,7 @@ func TestL1Oracle_GasPrice(t *testing.T) { l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) require.NoError(t, err) - isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) - require.NoError(t, err) - - ethClient := mocks.NewL1OracleClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - var payload []byte - payload, err = isEcotoneAbiString.Pack("isEcotone") - require.NoError(t, err) - require.Equal(t, payload, callMsg.Data) - assert.Nil(t, blockNumber) - }).Return(nil, errors.New("not ecotone")).Once() + ethClient := setupUpgradeCheck(t, OPGasOracleAddress, false, false) // Ecotone, Fjord disabled ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) @@ -141,7 +121,8 @@ func TestL1Oracle_GasPrice(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, OPGasOracleAddress) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock) + require.NoError(t, err) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(tests.Context(t)) @@ -155,19 +136,7 @@ func TestL1Oracle_GasPrice(t *testing.T) { l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) require.NoError(t, err) - isEcotoneAbiString, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) - require.NoError(t, err) - - ethClient := mocks.NewL1OracleClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - var payload []byte - payload, err = isEcotoneAbiString.Pack("isEcotone") - require.NoError(t, err) - require.Equal(t, payload, callMsg.Data) - assert.Nil(t, blockNumber) - }).Return(nil, errors.New("not ecotone")).Once() + ethClient := setupUpgradeCheck(t, ScrollGasOracleAddress, false, false) // Ecotone, Fjord disabled ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) @@ -179,9 +148,9 @@ func TestL1Oracle_GasPrice(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainScroll) - require.NoError(t, oracle.Start(tests.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainScroll) + require.NoError(t, err) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(tests.Context(t)) require.NoError(t, err) @@ -216,9 +185,9 @@ func TestL1Oracle_GasPrice(t *testing.T) { assert.Nil(t, blockNumber) }).Return(common.BigToHash(gasPerPubByteL2).Bytes(), nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainZkSync) - require.NoError(t, oracle.Start(tests.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainZkSync) + require.NoError(t, err) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(tests.Context(t)) require.NoError(t, err) @@ -260,7 +229,8 @@ func TestL1Oracle_GetGasCost(t *testing.T) { require.Equal(t, blockNum, blockNumber) }).Return(result, nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainArbitrum) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainArbitrum) + require.NoError(t, err) gasCost, err := oracle.GetGasCost(tests.Context(t), tx, blockNum) require.NoError(t, err) @@ -272,9 +242,10 @@ func TestL1Oracle_GetGasCost(t *testing.T) { tx := types.NewTx(&types.LegacyTx{}) ethClient := mocks.NewL1OracleClient(t) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainKroma) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainKroma) + require.NoError(t, err) - _, err := oracle.GetGasCost(tests.Context(t), tx, blockNum) + _, err = oracle.GetGasCost(tests.Context(t), tx, blockNum) require.Error(t, err, "L1 gas cost not supported for this chain: kroma") }) @@ -306,7 +277,8 @@ func TestL1Oracle_GetGasCost(t *testing.T) { require.Equal(t, blockNum, blockNumber) }).Return(common.BigToHash(l1GasCost).Bytes(), nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock) + require.NoError(t, err) gasCost, err := oracle.GetGasCost(tests.Context(t), tx, blockNum) require.NoError(t, err) @@ -341,7 +313,8 @@ func TestL1Oracle_GetGasCost(t *testing.T) { require.Equal(t, blockNum, blockNumber) }).Return(common.BigToHash(l1GasCost).Bytes(), nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainScroll) + oracle, err := NewL1GasOracle(logger.Test(t), ethClient, chaintype.ChainScroll) + require.NoError(t, err) gasCost, err := oracle.GetGasCost(tests.Context(t), tx, blockNum) require.NoError(t, err) diff --git a/core/chains/evm/gas/rollups/mocks/da_price_reader.go b/core/chains/evm/gas/rollups/mocks/da_price_reader.go deleted file mode 100644 index 4157eb1494c..00000000000 --- a/core/chains/evm/gas/rollups/mocks/da_price_reader.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - big "math/big" - - mock "github.com/stretchr/testify/mock" -) - -// DAPriceReader is an autogenerated mock type for the daPriceReader type -type DAPriceReader struct { - mock.Mock -} - -// GetDAGasPrice provides a mock function with given fields: ctx -func (_m *DAPriceReader) GetDAGasPrice(ctx context.Context) (*big.Int, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetDAGasPrice") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewDAPriceReader creates a new instance of DAPriceReader. 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 NewDAPriceReader(t interface { - mock.TestingT - Cleanup(func()) -}) *DAPriceReader { - mock := &DAPriceReader{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index 79d4d64ecdf..f9f0a34b8a7 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go b/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go index 146f2cd6809..9225c247ca4 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/gas/rollups/op_l1_oracle.go b/core/chains/evm/gas/rollups/op_l1_oracle.go index 1977d139f9c..6805cd7095b 100644 --- a/core/chains/evm/gas/rollups/op_l1_oracle.go +++ b/core/chains/evm/gas/rollups/op_l1_oracle.go @@ -14,11 +14,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" - - gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -27,64 +26,76 @@ import ( ) // Reads L2-specific precompiles and caches the l1GasPrice set by the L2. -type OptimismL1Oracle struct { +type optimismL1Oracle struct { services.StateMachine client l1OracleClient pollPeriod time.Duration logger logger.SugaredLogger chainType chaintype.ChainType - l1OracleAddress string - gasPriceMethod string - l1GasPriceMethodAbi abi.ABI - l1GasPriceMu sync.RWMutex - l1GasPrice priceEntry - - gasCostMethod string - l1GasCostMethodAbi abi.ABI + l1OracleAddress string + l1GasPriceMu sync.RWMutex + l1GasPrice priceEntry + isEcotone bool + isFjord bool + upgradeCheckTs time.Time chInitialised chan struct{} chStop services.StopChan chDone chan struct{} - isEcotoneMethodAbi abi.ABI - - l1BaseFeeCalldata []byte - isEcotoneCalldata []byte - getL1GasUsedCalldata []byte - getL1FeeCalldata []byte - - isEcotone bool - isEcotoneCheckTs int64 + getL1FeeMethodAbi abi.ABI + l1BaseFeeCalldata []byte + baseFeeScalarCalldata []byte + blobBaseFeeCalldata []byte + blobBaseFeeScalarCalldata []byte + decimalsCalldata []byte + isEcotoneCalldata []byte + isEcotoneMethodAbi abi.ABI + isFjordCalldata []byte + isFjordMethodAbi abi.ABI } const ( - // OPStackGasOracle_isEcotone fetches if the OP Stack GasPriceOracle contract has upgraded to Ecotone - OPStackGasOracle_isEcotone = "isEcotone" - // OPStackGasOracle_getL1GasUsed fetches the l1 gas used for given tx bytes - OPStackGasOracle_getL1GasUsed = "getL1GasUsed" - // OPStackGasOracle_isEcotonePollingPeriod is the interval to poll if chain has upgraded to Ecotone - // Set to poll every 4 hours - OPStackGasOracle_isEcotonePollingPeriod = 14400 - // OPStackGasOracleAddress is the address of the precompiled contract that exists on OP stack chain. - // OPStackGasOracle_l1BaseFee fetches the l1 base fee set in the OP Stack GasPriceOracle contract - // OPStackGasOracle_l1BaseFee is a hex encoded call to: - // `function l1BaseFee() external view returns (uint256);` - OPStackGasOracle_l1BaseFee = "l1BaseFee" - // OPStackGasOracle_getL1Fee fetches the l1 fee for given tx bytes - // OPStackGasOracle_getL1Fee is a hex encoded call to: + // upgradePollingPeriod is the interval to poll if chain has been upgraded + upgradePollingPeriod = 4 * time.Hour + // isEcotone fetches if the OP Stack GasPriceOracle contract has upgraded to Ecotone + isEcotoneMethod = "isEcotone" + // isFjord fetches if the OP Stack GasPriceOracle contract has upgraded to Fjord + isFjordMethod = "isFjord" + // getL1Fee fetches the l1 fee for given tx bytes + // getL1Fee is a hex encoded call to: // `function getL1Fee(bytes) external view returns (uint256);` - OPStackGasOracle_getL1Fee = "getL1Fee" - // This is the case for Optimism and Base. + getL1FeeMethod = "getL1Fee" + // l1BaseFee fetches the l1 base fee set in the OP Stack GasPriceOracle contract + // l1BaseFee is a hex encoded call to: + // `function l1BaseFee() external view returns (uint256);` + l1BaseFeeMethod = "l1BaseFee" + // baseFeeScalar fetches the l1 base fee scalar for gas price calculation + // baseFeeScalar is a hex encoded call to: + // `function baseFeeScalar() public view returns (uint32);` + baseFeeScalarMethod = "baseFeeScalar" + // blobBaseFee fetches the l1 blob base fee for gas price calculation + // blobBaseFee is a hex encoded call to: + // `function blobBaseFee() public view returns (uint256);` + blobBaseFeeMethod = "blobBaseFee" + // blobBaseFeeScalar fetches the l1 blob base fee scalar for gas price calculation + // blobBaseFeeScalar is a hex encoded call to: + // `function blobBaseFeeScalar() public view returns (uint32);` + blobBaseFeeScalarMethod = "blobBaseFeeScalar" + // decimals fetches the number of decimals used in the scalar for gas price calculation + // decimals is a hex encoded call to: + // `function decimals() public pure returns (uint256);` + decimalsMethod = "decimals" + // OPGasOracleAddress is the address of the precompiled contract that exists on Optimism and Base. OPGasOracleAddress = "0x420000000000000000000000000000000000000F" - // GasOracleAddress is the address of the precompiled contract that exists on Kroma chain. - // This is the case for Kroma. + // KromaGasOracleAddress is the address of the precompiled contract that exists on Kroma. KromaGasOracleAddress = "0x4200000000000000000000000000000000000005" - // ScrollGasOracleAddress is the address of the precompiled contract that exists on Scroll chain. + // ScrollGasOracleAddress is the address of the precompiled contract that exists on Scroll. ScrollGasOracleAddress = "0x5300000000000000000000000000000000000002" ) -func NewOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType) *OptimismL1Oracle { +func NewOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType) (*optimismL1Oracle, error) { var precompileAddress string switch chainType { case chaintype.ChainOptimismBedrock: @@ -94,106 +105,128 @@ func NewOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainTy case chaintype.ChainScroll: precompileAddress = ScrollGasOracleAddress default: - panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) + return nil, fmt.Errorf("received unsupported chaintype %s", chainType) } return newOpStackL1GasOracle(lggr, ethClient, chainType, precompileAddress) } -func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType, precompileAddress string) *OptimismL1Oracle { - var l1OracleAddress, gasPriceMethod, gasCostMethod string - var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI - var gasPriceErr, gasCostErr error - - l1OracleAddress = precompileAddress - gasPriceMethod = OPStackGasOracle_l1BaseFee - l1GasPriceMethodAbi, gasPriceErr = abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - gasCostMethod = OPStackGasOracle_getL1Fee - l1GasCostMethodAbi, gasCostErr = abi.JSON(strings.NewReader(GetL1FeeAbiString)) - - if gasPriceErr != nil { - panic(fmt.Sprintf("Failed to parse L1 gas price method ABI for chain: %s", chainType)) - } - if gasCostErr != nil { - panic(fmt.Sprintf("Failed to parse L1 gas cost method ABI for chain: %s", chainType)) +func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType, precompileAddress string) (*optimismL1Oracle, error) { + getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + if err != nil { + return nil, fmt.Errorf("failed to parse L1 gas cost method ABI for chain: %s", chainType) } // encode calldata for each method; these calldata will remain the same for each call, we can encode them just once + // Encode calldata for l1BaseFee method l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", l1BaseFeeMethod, chainType, err) } - l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(l1BaseFeeMethod) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", l1BaseFeeMethod, chainType, err) } + // Encode calldata for isEcotone method isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", isEcotoneMethod, chainType, err) } - isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(isEcotoneMethod) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", isEcotoneMethod, chainType, err) } - getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) + // Encode calldata for isFjord method + isFjordMethodAbi, err := abi.JSON(strings.NewReader(OPIsFjordAbiString)) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", isFjordMethod, chainType, err) } - getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) + isFjordCalldata, err := isFjordMethodAbi.Pack(isFjordMethod) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", isFjordMethod, chainType, err) } - getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + // Encode calldata for baseFeeScalar method + baseFeeScalarMethodAbi, err := abi.JSON(strings.NewReader(OPBaseFeeScalarAbiString)) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", baseFeeScalarMethod, chainType, err) } - getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) + baseFeeScalarCalldata, err := baseFeeScalarMethodAbi.Pack(baseFeeScalarMethod) if err != nil { - panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", baseFeeScalarMethod, chainType, err) } - return &OptimismL1Oracle{ + // Encode calldata for blobBaseFee method + blobBaseFeeMethodAbi, err := abi.JSON(strings.NewReader(OPBlobBaseFeeAbiString)) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", blobBaseFeeMethod, chainType, err) + } + blobBaseFeeCalldata, err := blobBaseFeeMethodAbi.Pack(blobBaseFeeMethod) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", blobBaseFeeMethod, chainType, err) + } + + // Encode calldata for blobBaseFeeScalar method + blobBaseFeeScalarMethodAbi, err := abi.JSON(strings.NewReader(OPBlobBaseFeeScalarAbiString)) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", blobBaseFeeScalarMethod, chainType, err) + } + blobBaseFeeScalarCalldata, err := blobBaseFeeScalarMethodAbi.Pack(blobBaseFeeScalarMethod) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", blobBaseFeeScalarMethod, chainType, err) + } + + // Encode calldata for decimals method + decimalsMethodAbi, err := abi.JSON(strings.NewReader(OPDecimalsAbiString)) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", decimalsMethod, chainType, err) + } + decimalsCalldata, err := decimalsMethodAbi.Pack(decimalsMethod) + if err != nil { + return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", decimalsMethod, chainType, err) + } + + return &optimismL1Oracle{ client: ethClient, pollPeriod: PollPeriod, - logger: logger.Sugared(logger.Named(lggr, "L1GasOracle(optimismBedrock)")), + logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("L1GasOracle(%s)", chainType))), chainType: chainType, - l1OracleAddress: l1OracleAddress, - gasPriceMethod: gasPriceMethod, - l1GasPriceMethodAbi: l1GasPriceMethodAbi, - gasCostMethod: gasCostMethod, - l1GasCostMethodAbi: l1GasCostMethodAbi, + l1OracleAddress: precompileAddress, + isEcotone: false, + isFjord: false, + upgradeCheckTs: time.Time{}, chInitialised: make(chan struct{}), chStop: make(chan struct{}), chDone: make(chan struct{}), - isEcotoneMethodAbi: isEcotoneMethodAbi, - - l1BaseFeeCalldata: l1BaseFeeCalldata, - isEcotoneCalldata: isEcotoneCalldata, - getL1GasUsedCalldata: getL1GasUsedCalldata, - getL1FeeCalldata: getL1FeeCalldata, - - isEcotone: false, - isEcotoneCheckTs: 0, - } + getL1FeeMethodAbi: getL1FeeMethodAbi, + l1BaseFeeCalldata: l1BaseFeeCalldata, + baseFeeScalarCalldata: baseFeeScalarCalldata, + blobBaseFeeCalldata: blobBaseFeeCalldata, + blobBaseFeeScalarCalldata: blobBaseFeeScalarCalldata, + decimalsCalldata: decimalsCalldata, + isEcotoneCalldata: isEcotoneCalldata, + isEcotoneMethodAbi: isEcotoneMethodAbi, + isFjordCalldata: isFjordCalldata, + isFjordMethodAbi: isFjordMethodAbi, + }, nil } -func (o *OptimismL1Oracle) Name() string { +func (o *optimismL1Oracle) Name() string { return o.logger.Name() } -func (o *OptimismL1Oracle) Start(ctx context.Context) error { +func (o *optimismL1Oracle) Start(ctx context.Context) error { return o.StartOnce(o.Name(), func() error { go o.run() <-o.chInitialised return nil }) } -func (o *OptimismL1Oracle) Close() error { +func (o *optimismL1Oracle) Close() error { return o.StopOnce(o.Name(), func() error { close(o.chStop) <-o.chDone @@ -201,51 +234,55 @@ func (o *OptimismL1Oracle) Close() error { }) } -func (o *OptimismL1Oracle) HealthReport() map[string]error { +func (o *optimismL1Oracle) HealthReport() map[string]error { return map[string]error{o.Name(): o.Healthy()} } -func (o *OptimismL1Oracle) run() { +func (o *optimismL1Oracle) run() { defer close(o.chDone) - t := o.refresh() + o.refresh() close(o.chInitialised) + t := services.TickerConfig{ + Initial: o.pollPeriod, + JitterPct: services.DefaultJitter, + }.NewTicker(o.pollPeriod) + defer t.Stop() + for { select { case <-o.chStop: return case <-t.C: - t = o.refresh() + o.refresh() } } } -func (o *OptimismL1Oracle) refresh() (t *time.Timer) { - t, err := o.refreshWithError() +func (o *optimismL1Oracle) refresh() { + err := o.refreshWithError() if err != nil { + o.logger.Criticalw("Failed to refresh gas price", "err", err) o.SvcErrBuffer.Append(err) } - return } -func (o *OptimismL1Oracle) refreshWithError() (t *time.Timer, err error) { - t = time.NewTimer(utils.WithJitter(o.pollPeriod)) - +func (o *optimismL1Oracle) refreshWithError() error { ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) defer cancel() price, err := o.GetDAGasPrice(ctx) if err != nil { - return t, err + return err } o.l1GasPriceMu.Lock() defer o.l1GasPriceMu.Unlock() o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} - return + return nil } -func (o *OptimismL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { +func (o *optimismL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { var timestamp time.Time ok := o.IfStarted(func() { o.l1GasPriceMu.RLock() @@ -269,7 +306,7 @@ func (o *OptimismL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, // Gets the L1 gas cost for the provided transaction at the specified block num // If block num is not provided, the value on the latest block num is used -func (o *OptimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { +func (o *optimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { ctx, cancel := context.WithTimeout(ctx, client.QueryTimeout) defer cancel() var callData, b []byte @@ -282,7 +319,7 @@ func (o *OptimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transac if encodedtx, err = tx.MarshalBinary(); err != nil { return nil, fmt.Errorf("failed to marshal tx for gas cost estimation: %w", err) } - if callData, err = o.l1GasCostMethodAbi.Pack(o.gasCostMethod, encodedtx); err != nil { + if callData, err = o.getL1FeeMethodAbi.Pack(getL1FeeMethod, encodedtx); err != nil { return nil, fmt.Errorf("failed to pack calldata for %s L1 gas cost estimation method: %w", o.chainType, err) } @@ -308,54 +345,89 @@ func (o *OptimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transac return assets.NewWei(l1GasCost), nil } -func (o *OptimismL1Oracle) GetDAGasPrice(ctx context.Context) (*big.Int, error) { - isEcotone, err := o.checkIsEcotone(ctx) +func (o *optimismL1Oracle) GetDAGasPrice(ctx context.Context) (*big.Int, error) { + err := o.checkForUpgrade(ctx) if err != nil { return nil, err } - - o.logger.Infof("Chain isEcotone result: %t", isEcotone) - - if isEcotone { - return o.getEcotoneGasPrice(ctx) + if o.isFjord || o.isEcotone { + return o.getEcotoneFjordGasPrice(ctx) } return o.getV1GasPrice(ctx) } -func (o *OptimismL1Oracle) checkIsEcotone(ctx context.Context) (bool, error) { - // if chain is already Ecotone, NOOP - if o.isEcotone { - return true, nil +// Checks oracle flags for Ecotone and Fjord upgrades +func (o *optimismL1Oracle) checkForUpgrade(ctx context.Context) error { + // if chain is already Fjord (the latest upgrade), NOOP + // need to continue to check if not on latest upgrade + if o.isFjord { + return nil } // if time since last check has not exceeded polling period, NOOP - if time.Now().Unix()-o.isEcotoneCheckTs < OPStackGasOracle_isEcotonePollingPeriod { - return false, nil + if time.Since(o.upgradeCheckTs) < upgradePollingPeriod { + return nil } - o.isEcotoneCheckTs = time.Now().Unix() - - l1OracleAddress := common.HexToAddress(o.l1OracleAddress) - // confirmed with OP team that isEcotone() is the canonical way to check if the chain has upgraded - b, err := o.client.CallContract(ctx, ethereum.CallMsg{ - To: &l1OracleAddress, - Data: o.isEcotoneCalldata, - }, nil) - - // if the chain has not upgraded to Ecotone, the isEcotone call will revert, this would be expected - if err != nil { - o.logger.Infof("isEcotone() call failed, this can happen if chain has not upgraded: %v", err) - return false, nil + o.upgradeCheckTs = time.Now() + rpcBatchCalls := []rpc.BatchElem{ + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.isFjordCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.isEcotoneCalldata), + }, + "latest", + }, + Result: new(string), + }, } - - res, err := o.isEcotoneMethodAbi.Unpack(OPStackGasOracle_isEcotone, b) + err := o.client.BatchCallContext(ctx, rpcBatchCalls) if err != nil { - return false, fmt.Errorf("failed to unpack isEcotone() return data: %w", err) + return fmt.Errorf("check upgrade batch call failed: %w", err) + } + // These calls are expected to revert if chain has not upgraded. Ignore non-nil Error field. + if rpcBatchCalls[0].Error == nil { + result := *(rpcBatchCalls[0].Result.(*string)) + if b, decodeErr := hexutil.Decode(result); decodeErr == nil { + if res, unpackErr := o.isFjordMethodAbi.Unpack(isFjordMethod, b); unpackErr == nil { + o.isFjord = res[0].(bool) + } else { + o.logger.Errorw("failed to unpack results", "method", isFjordMethod, "hex", result, "error", unpackErr) + } + } else { + o.logger.Errorw("failed to decode bytes", "method", isFjordMethod, "hex", result, "error", decodeErr) + } + } + if rpcBatchCalls[1].Error == nil { + result := *(rpcBatchCalls[1].Result.(*string)) + if b, decodeErr := hexutil.Decode(result); decodeErr == nil { + if res, unpackErr := o.isEcotoneMethodAbi.Unpack(isEcotoneMethod, b); unpackErr == nil { + o.isEcotone = res[0].(bool) + } else { + o.logger.Errorw("failed to unpack results", "method", isEcotoneMethod, "hex", result, "error", unpackErr) + } + } else { + o.logger.Errorw("failed to decode bytes", "method", isEcotoneMethod, "hex", result, "error", decodeErr) + } } - o.isEcotone = res[0].(bool) - return o.isEcotone, nil + return nil } -func (o *OptimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error) { +func (o *optimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error) { l1OracleAddress := common.HexToAddress(o.l1OracleAddress) b, err := o.client.CallContract(ctx, ethereum.CallMsg{ To: &l1OracleAddress, @@ -371,7 +443,9 @@ func (o *OptimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error) return new(big.Int).SetBytes(b), nil } -func (o *OptimismL1Oracle) getEcotoneGasPrice(ctx context.Context) (*big.Int, error) { +// Returns the scaled gas price using baseFeeScalar, l1BaseFee, blobBaseFeeScalar, and blobBaseFee fields from the oracle +// Confirmed the same calculation is used to determine gas price for both Ecotone and Fjord +func (o *optimismL1Oracle) getEcotoneFjordGasPrice(ctx context.Context) (*big.Int, error) { rpcBatchCalls := []rpc.BatchElem{ { Method: "eth_call", @@ -379,7 +453,43 @@ func (o *OptimismL1Oracle) getEcotoneGasPrice(ctx context.Context) (*big.Int, er map[string]interface{}{ "from": common.Address{}, "to": o.l1OracleAddress, - "data": hexutil.Bytes(o.getL1GasUsedCalldata), + "data": hexutil.Bytes(o.l1BaseFeeCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.baseFeeScalarCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.blobBaseFeeCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.l1OracleAddress, + "data": hexutil.Bytes(o.blobBaseFeeScalarCalldata), }, "latest", }, @@ -391,7 +501,7 @@ func (o *OptimismL1Oracle) getEcotoneGasPrice(ctx context.Context) (*big.Int, er map[string]interface{}{ "from": common.Address{}, "to": o.l1OracleAddress, - "data": hexutil.Bytes(o.getL1FeeCalldata), + "data": hexutil.Bytes(o.decimalsCalldata), }, "latest", }, @@ -401,31 +511,75 @@ func (o *OptimismL1Oracle) getEcotoneGasPrice(ctx context.Context) (*big.Int, er err := o.client.BatchCallContext(ctx, rpcBatchCalls) if err != nil { - return nil, fmt.Errorf("getEcotoneGasPrice batch call failed: %w", err) + return nil, fmt.Errorf("fetch gas price parameters batch call failed: %w", err) } if rpcBatchCalls[0].Error != nil { - return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1GasUsed, err) + return nil, fmt.Errorf("%s call failed in a batch: %w", l1BaseFeeMethod, err) } if rpcBatchCalls[1].Error != nil { - return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1Fee, err) + return nil, fmt.Errorf("%s call failed in a batch: %w", baseFeeScalarMethod, err) + } + if rpcBatchCalls[2].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", blobBaseFeeMethod, err) + } + if rpcBatchCalls[3].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", blobBaseFeeScalarMethod, err) + } + if rpcBatchCalls[4].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", decimalsMethod, err) } - l1GasUsedResult := *(rpcBatchCalls[0].Result.(*string)) - l1FeeResult := *(rpcBatchCalls[1].Result.(*string)) + // Extract values from responses + l1BaseFeeResult := *(rpcBatchCalls[0].Result.(*string)) + baseFeeScalarResult := *(rpcBatchCalls[1].Result.(*string)) + blobBaseFeeResult := *(rpcBatchCalls[2].Result.(*string)) + blobBaseFeeScalarResult := *(rpcBatchCalls[3].Result.(*string)) + decimalsResult := *(rpcBatchCalls[4].Result.(*string)) - l1GasUsedBytes, err := hexutil.Decode(l1GasUsedResult) + // Decode the responses into bytes + l1BaseFeeBytes, err := hexutil.Decode(l1BaseFeeResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", l1BaseFeeMethod, err) + } + baseFeeScalarBytes, err := hexutil.Decode(baseFeeScalarResult) if err != nil { - return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1GasUsed, err) + return nil, fmt.Errorf("failed to decode %s rpc result: %w", baseFeeScalarMethod, err) } - l1FeeBytes, err := hexutil.Decode(l1FeeResult) + blobBaseFeeBytes, err := hexutil.Decode(blobBaseFeeResult) if err != nil { - return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1Fee, err) + return nil, fmt.Errorf("failed to decode %s rpc result: %w", blobBaseFeeMethod, err) } + blobBaseFeeScalarBytes, err := hexutil.Decode(blobBaseFeeScalarResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", blobBaseFeeScalarMethod, err) + } + decimalsBytes, err := hexutil.Decode(decimalsResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", decimalsMethod, err) + } + + // Convert bytes to big int for calculations + l1BaseFee := new(big.Int).SetBytes(l1BaseFeeBytes) + baseFeeScalar := new(big.Int).SetBytes(baseFeeScalarBytes) + blobBaseFee := new(big.Int).SetBytes(blobBaseFeeBytes) + blobBaseFeeScalar := new(big.Int).SetBytes(blobBaseFeeScalarBytes) + decimals := new(big.Int).SetBytes(decimalsBytes) + + o.logger.Debugw("gas price parameters", "l1BaseFee", l1BaseFee, "baseFeeScalar", baseFeeScalar, "blobBaseFee", blobBaseFee, "blobBaseFeeScalar", blobBaseFeeScalar, "decimals", decimals) + + // Scaled gas price = baseFee * 16 * baseFeeScalar + blobBaseFee * blobBaseFeeScalar + scaledBaseFee := new(big.Int).Mul(l1BaseFee, baseFeeScalar) + scaledBaseFee = new(big.Int).Mul(scaledBaseFee, big.NewInt(16)) + scaledBlobBaseFee := new(big.Int).Mul(blobBaseFee, blobBaseFeeScalar) + scaledGasPrice := new(big.Int).Add(scaledBaseFee, scaledBlobBaseFee) - l1GasUsed := new(big.Int).SetBytes(l1GasUsedBytes) - l1Fee := new(big.Int).SetBytes(l1FeeBytes) + // Gas price = scaled gas price / (16 * 10 ^ decimals) + // This formula is extracted from the gas cost methods in the precompile contract + // Note: The Fjord calculation in the contract uses estimated size instead of gas used which is why we have to scale down by (16 * 10 ^ decimals) as well + // Ecotone: https://github.com/ethereum-optimism/optimism/blob/71b93116738ee98c9f8713b1a5dfe626ce06c1b2/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L192 + // Fjord: https://github.com/ethereum-optimism/optimism/blob/71b93116738ee98c9f8713b1a5dfe626ce06c1b2/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L229-L230 + scale := new(big.Int).Exp(big.NewInt(10), decimals, nil) + scale = new(big.Int).Mul(scale, big.NewInt(16)) - // for the same tx byte, l1Fee / l1GasUsed will give the l1 gas price - // note this price is per l1 gas, not l1 data byte - return new(big.Int).Div(l1Fee, l1GasUsed), nil + return new(big.Int).Div(scaledGasPrice, scale), nil } diff --git a/core/chains/evm/gas/rollups/op_l1_oracle_test.go b/core/chains/evm/gas/rollups/op_l1_oracle_test.go index 86fdbe0a62d..f5f009f1ea6 100644 --- a/core/chains/evm/gas/rollups/op_l1_oracle_test.go +++ b/core/chains/evm/gas/rollups/op_l1_oracle_test.go @@ -22,26 +22,28 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" ) -func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { +func TestOPL1Oracle_ReadV1GasPrice(t *testing.T) { t.Parallel() testCases := []struct { name string isEcotoneError bool - returnBadData bool + isFjordError bool }{ { - name: "calling isEcotone returns false, fetches l1BaseFee", + name: "calling isEcotone and isFjord returns false, fetches l1BaseFee", isEcotoneError: false, + isFjordError: false, }, { - name: "calling isEcotone when chain has not made Ecotone upgrade, fetches l1BaseFee", - isEcotoneError: true, + name: "calling isEcotone returns false and IsFjord errors when chain has not made Fjord upgrade, fetches l1BaseFee", + isEcotoneError: false, + isFjordError: true, }, { - name: "calling isEcotone returns bad data, returns error", - isEcotoneError: false, - returnBadData: true, + name: "calling isEcotone and isFjord when chain has not made Ecotone upgrade, fetches l1BaseFee", + isEcotoneError: true, + isFjordError: true, }, } @@ -52,117 +54,252 @@ func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) require.NoError(t, err) - l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(l1BaseFeeMethod) require.NoError(t, err) + // IsFjord calldata + isFjordMethodAbi, err := abi.JSON(strings.NewReader(OPIsFjordAbiString)) + require.NoError(t, err) + isFjordCalldata, err := isFjordMethodAbi.Pack(isFjordMethod) + require.NoError(t, err) + + // IsEcotone calldata isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) require.NoError(t, err) - isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(isEcotoneMethod) require.NoError(t, err) ethClient := mocks.NewL1OracleClient(t) - call := ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + require.Equal(t, 2, len(rpcElements)) + for _, rE := range rpcElements { + require.Equal(t, "eth_call", rE.Method) + require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"]) + require.Equal(t, "latest", rE.Args[1]) + } + require.Equal(t, hexutil.Bytes(isFjordCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(isEcotoneCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"]) + isUpgraded := "0x0000000000000000000000000000000000000000000000000000000000000000" + if tc.isFjordError { + rpcElements[0].Error = fmt.Errorf("test error") + } else { + rpcElements[0].Result = &isUpgraded + } + if tc.isEcotoneError { + rpcElements[1].Error = fmt.Errorf("test error") + } else { + rpcElements[1].Result = &isUpgraded + } + }).Return(nil).Once() + + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { callMsg := args.Get(1).(ethereum.CallMsg) blockNumber := args.Get(2).(*big.Int) - require.Equal(t, isEcotoneCalldata, callMsg.Data) + require.Equal(t, l1BaseFeeCalldata, callMsg.Data) require.Equal(t, oracleAddress, callMsg.To.String()) assert.Nil(t, blockNumber) - }) - - if tc.returnBadData { - call.Return([]byte{0x2, 0x2}, nil).Once() - } else if tc.isEcotoneError { - call.Return(nil, fmt.Errorf("test error")).Once() - } else { - call.Return(isEcotoneMethodAbi.Methods["isEcotone"].Outputs.Pack(false)).Once() - } - - if !tc.returnBadData { - 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) - require.Equal(t, l1BaseFeeCalldata, callMsg.Data) - require.Equal(t, oracleAddress, callMsg.To.String()) - assert.Nil(t, blockNumber) - }).Return(common.BigToHash(l1BaseFee).Bytes(), nil).Once() - } - - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil).Once() + + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) gasPrice, err := oracle.GetDAGasPrice(tests.Context(t)) - if tc.returnBadData { - assert.Error(t, err) - } else { - require.NoError(t, err) - assert.Equal(t, l1BaseFee, gasPrice) - } + require.NoError(t, err) + assert.Equal(t, l1BaseFee, gasPrice) }) } } -func setupIsEcotone(t *testing.T, oracleAddress string) *mocks.L1OracleClient { +func setupUpgradeCheck(t *testing.T, oracleAddress string, isFjord, isEcotone bool) *mocks.L1OracleClient { + trueHex := "0x0000000000000000000000000000000000000000000000000000000000000001" + falseHex := "0x0000000000000000000000000000000000000000000000000000000000000000" + boolToHexMap := map[bool]*string{ + true: &trueHex, + false: &falseHex, + } + // IsFjord calldata + isFjordMethodAbi, err := abi.JSON(strings.NewReader(OPIsFjordAbiString)) + require.NoError(t, err) + isFjordCalldata, err := isFjordMethodAbi.Pack(isFjordMethod) + require.NoError(t, err) + + // IsEcotone calldata isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) require.NoError(t, err) - isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(isEcotoneMethod) require.NoError(t, err) ethClient := mocks.NewL1OracleClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - require.Equal(t, isEcotoneCalldata, callMsg.Data) - require.Equal(t, oracleAddress, callMsg.To.String()) - assert.Nil(t, blockNumber) - }).Return(isEcotoneMethodAbi.Methods["isEcotone"].Outputs.Pack(true)).Once() + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + require.Equal(t, 2, len(rpcElements)) + for _, rE := range rpcElements { + require.Equal(t, "eth_call", rE.Method) + require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"]) + require.Equal(t, "latest", rE.Args[1]) + } + require.Equal(t, hexutil.Bytes(isFjordCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(isEcotoneCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"]) + + rpcElements[0].Result = boolToHexMap[isFjord] + rpcElements[1].Result = boolToHexMap[isEcotone] + }).Return(nil).Once() return ethClient } -func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { - l1BaseFee := big.NewInt(100) +func mockBatchContractCall(t *testing.T, ethClient *mocks.L1OracleClient, oracleAddress string, baseFeeVal, baseFeeScalarVal, blobBaseFeeVal, blobBaseFeeScalarVal, decimalsVal *big.Int) { + // L1 base fee calldata + l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + require.NoError(t, err) + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(l1BaseFeeMethod) + require.NoError(t, err) + + // L1 base fee scalar calldata + l1BaseFeeScalarMethodAbi, err := abi.JSON(strings.NewReader(OPBaseFeeScalarAbiString)) + require.NoError(t, err) + l1BaseFeeScalarCalldata, err := l1BaseFeeScalarMethodAbi.Pack(baseFeeScalarMethod) + require.NoError(t, err) + + // Blob base fee calldata + blobBaseFeeMethodAbi, err := abi.JSON(strings.NewReader(OPBlobBaseFeeAbiString)) + require.NoError(t, err) + blobBaseFeeCalldata, err := blobBaseFeeMethodAbi.Pack(blobBaseFeeMethod) + require.NoError(t, err) + + // Blob base fee scalar calldata + blobBaseFeeScalarMethodAbi, err := abi.JSON(strings.NewReader(OPBlobBaseFeeScalarAbiString)) + require.NoError(t, err) + blobBaseFeeScalarCalldata, err := blobBaseFeeScalarMethodAbi.Pack(blobBaseFeeScalarMethod) + require.NoError(t, err) + + // Decimals calldata + decimalsMethodAbi, err := abi.JSON(strings.NewReader(OPDecimalsAbiString)) + require.NoError(t, err) + decimalsCalldata, err := decimalsMethodAbi.Pack(decimalsMethod) + require.NoError(t, err) + + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + require.Equal(t, 5, len(rpcElements)) + + for _, rE := range rpcElements { + require.Equal(t, "eth_call", rE.Method) + require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"]) + require.Equal(t, "latest", rE.Args[1]) + } + + require.Equal(t, hexutil.Bytes(l1BaseFeeCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(l1BaseFeeScalarCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(blobBaseFeeCalldata), rpcElements[2].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(blobBaseFeeScalarCalldata), rpcElements[3].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(decimalsCalldata), rpcElements[4].Args[0].(map[string]interface{})["data"]) + + res1 := common.BigToHash(baseFeeVal).Hex() + res2 := common.BigToHash(baseFeeScalarVal).Hex() + res3 := common.BigToHash(blobBaseFeeVal).Hex() + res4 := common.BigToHash(blobBaseFeeScalarVal).Hex() + res5 := common.BigToHash(decimalsVal).Hex() + rpcElements[0].Result = &res1 + rpcElements[1].Result = &res2 + rpcElements[2].Result = &res3 + rpcElements[3].Result = &res4 + rpcElements[4].Result = &res5 + }).Return(nil).Once() +} + +func TestOPL1Oracle_CalculateEcotoneGasPrice(t *testing.T) { + baseFee := big.NewInt(100000000) + blobBaseFee := big.NewInt(25000000) + baseFeeScalar := big.NewInt(10) + blobBaseFeeScalar := big.NewInt(5) + decimals := big.NewInt(6) oracleAddress := common.HexToAddress("0x1234").String() t.Parallel() t.Run("correctly fetches weighted gas price if chain has upgraded to Ecotone", func(t *testing.T) { - ethClient := setupIsEcotone(t, oracleAddress) - getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) + ethClient := setupUpgradeCheck(t, oracleAddress, false, true) + mockBatchContractCall(t, ethClient, oracleAddress, baseFee, baseFeeScalar, blobBaseFee, blobBaseFeeScalar, decimals) + + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) require.NoError(t, err) - getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) + gasPrice, err := oracle.GetDAGasPrice(tests.Context(t)) require.NoError(t, err) + scaledGasPrice := big.NewInt(16125000000) // baseFee * scalar * 16 + blobBaseFee * scalar + scale := big.NewInt(16000000) // Scaled by 16 * 10 ^ decimals + expectedGasPrice := new(big.Int).Div(scaledGasPrice, scale) + assert.Equal(t, expectedGasPrice, gasPrice) + }) - getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + t.Run("fetching Ecotone price but rpc returns bad data", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, false, true) + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + var badData = "zzz" + rpcElements[0].Result = &badData + rpcElements[1].Result = &badData + }).Return(nil).Once() + + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) require.NoError(t, err) - getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) + _, err = oracle.GetDAGasPrice(tests.Context(t)) + assert.Error(t, err) + }) + + t.Run("fetching Ecotone price but rpc parent call errors", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, false, true) + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once() + + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) require.NoError(t, err) + _, err = oracle.GetDAGasPrice(tests.Context(t)) + assert.Error(t, err) + }) + t.Run("fetching Ecotone price but one of the sub rpc call errors", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, false, true) ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { rpcElements := args.Get(1).([]rpc.BatchElem) - require.Equal(t, 2, len(rpcElements)) + res := common.BigToHash(baseFee).Hex() + rpcElements[0].Result = &res + rpcElements[1].Error = fmt.Errorf("revert") + }).Return(nil).Once() - for _, rE := range rpcElements { - require.Equal(t, "eth_call", rE.Method) - require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"]) - require.Equal(t, "latest", rE.Args[1]) - } + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) + _, err = oracle.GetDAGasPrice(tests.Context(t)) + assert.Error(t, err) + }) +} - require.Equal(t, hexutil.Bytes(getL1GasUsedCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"]) - require.Equal(t, hexutil.Bytes(getL1FeeCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"]) +func TestOPL1Oracle_CalculateFjordGasPrice(t *testing.T) { + baseFee := big.NewInt(100000000) + blobBaseFee := big.NewInt(25000000) + baseFeeScalar := big.NewInt(10) + blobBaseFeeScalar := big.NewInt(5) + decimals := big.NewInt(6) + oracleAddress := common.HexToAddress("0x1234").String() - res1 := common.BigToHash(big.NewInt(1)).Hex() - res2 := common.BigToHash(l1BaseFee).Hex() - rpcElements[0].Result = &res1 - rpcElements[1].Result = &res2 - }).Return(nil).Once() + t.Parallel() - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + t.Run("correctly fetches gas price if chain has upgraded to Fjord", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, true, true) + mockBatchContractCall(t, ethClient, oracleAddress, baseFee, baseFeeScalar, blobBaseFee, blobBaseFeeScalar, decimals) + + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) gasPrice, err := oracle.GetDAGasPrice(tests.Context(t)) require.NoError(t, err) - assert.Equal(t, l1BaseFee, gasPrice) + scaledGasPrice := big.NewInt(16125000000) // baseFee * scalar * 16 + blobBaseFee * scalar + scale := big.NewInt(16000000) // Scaled by 16 * 10 ^ decimals + expectedGasPrice := new(big.Int).Div(scaledGasPrice, scale) + assert.Equal(t, expectedGasPrice, gasPrice) }) - t.Run("fetching Ecotone price but rpc returns bad data", func(t *testing.T) { - ethClient := setupIsEcotone(t, oracleAddress) + t.Run("fetching Fjord price but rpc returns bad data", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, true, true) ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { rpcElements := args.Get(1).([]rpc.BatchElem) var badData = "zzz" @@ -170,31 +307,34 @@ func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { rpcElements[1].Result = &badData }).Return(nil).Once() - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) - _, err := oracle.GetDAGasPrice(tests.Context(t)) + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) + _, err = oracle.GetDAGasPrice(tests.Context(t)) assert.Error(t, err) }) - t.Run("fetching Ecotone price but rpc parent call errors", func(t *testing.T) { - ethClient := setupIsEcotone(t, oracleAddress) + t.Run("fetching Fjord price but rpc parent call errors", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, true, true) ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once() - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) - _, err := oracle.GetDAGasPrice(tests.Context(t)) + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) + _, err = oracle.GetDAGasPrice(tests.Context(t)) assert.Error(t, err) }) - t.Run("fetching Ecotone price but one of the sub rpc call errors", func(t *testing.T) { - ethClient := setupIsEcotone(t, oracleAddress) + t.Run("fetching Fjord price but one of the sub rpc call errors", func(t *testing.T) { + ethClient := setupUpgradeCheck(t, oracleAddress, true, true) ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { rpcElements := args.Get(1).([]rpc.BatchElem) - res := common.BigToHash(l1BaseFee).Hex() + res := common.BigToHash(baseFee).Hex() rpcElements[0].Result = &res rpcElements[1].Error = fmt.Errorf("revert") }).Return(nil).Once() - oracle := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) - _, err := oracle.GetDAGasPrice(tests.Context(t)) + oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainOptimismBedrock, oracleAddress) + require.NoError(t, err) + _, err = oracle.GetDAGasPrice(tests.Context(t)) assert.Error(t, err) }) } diff --git a/core/chains/evm/gas/rollups/zkSync_l1_oracle.go b/core/chains/evm/gas/rollups/zkSync_l1_oracle.go index 00ee91b3f8a..31d93bc587d 100644 --- a/core/chains/evm/gas/rollups/zkSync_l1_oracle.go +++ b/core/chains/evm/gas/rollups/zkSync_l1_oracle.go @@ -120,6 +120,7 @@ func (o *zkSyncL1Oracle) run() { func (o *zkSyncL1Oracle) refresh() (t *time.Timer) { t, err := o.refreshWithError() if err != nil { + o.logger.Criticalw("Failed to refresh gas price", "err", err) o.SvcErrBuffer.Append(err) } return @@ -185,7 +186,7 @@ func (o *zkSyncL1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, er func (o *zkSyncL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transaction, blockNum *big.Int) (*assets.Wei, error) { //Unused method, so not implemented // And its not possible to know gas consumption of a transaction before its executed, since zkSync only posts the state difference - panic("unimplemented") + return nil, fmt.Errorf("unimplemented") } // GetL2GasPrice calls SystemContract.gasPrice() on the zksync system precompile contract. diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index 2c8798d6320..e8afee642af 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -12,7 +12,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/utils" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/fee" @@ -101,26 +100,29 @@ func (o *SuggestedPriceEstimator) HealthReport() map[string]error { func (o *SuggestedPriceEstimator) run() { defer close(o.chDone) - t := o.refreshPrice() + o.refreshPrice() close(o.chInitialised) + t := services.TickerConfig{ + Initial: o.pollPeriod, + JitterPct: services.DefaultJitter, + }.NewTicker(o.pollPeriod) + for { select { case <-o.chStop: return case ch := <-o.chForceRefetch: - t.Stop() - t = o.refreshPrice() + o.refreshPrice() + t.Reset() close(ch) case <-t.C: - t = o.refreshPrice() + o.refreshPrice() } } } -func (o *SuggestedPriceEstimator) refreshPrice() (t *time.Timer) { - t = time.NewTimer(utils.WithJitter(o.pollPeriod)) - +func (o *SuggestedPriceEstimator) refreshPrice() { var res hexutil.Big ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) defer cancel() @@ -136,7 +138,6 @@ func (o *SuggestedPriceEstimator) refreshPrice() (t *time.Timer) { o.gasPriceMu.Lock() defer o.gasPriceMu.Unlock() o.GasPrice = bi - return } // Uses the force refetch chan to trigger a price update and blocks until complete diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index 2da41de8774..7ac61ab34b0 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -60,8 +60,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { chchHeaders <- args.Get(1).(chan<- *evmtypes.Head) }). Return(sub, nil) - // 2 for initial and 2 for backfill - ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(testutils.Head(1), nil).Times(4) + ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(testutils.Head(1), nil) sub.On("Unsubscribe").Return() sub.On("Err").Return(nil) diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index 2e1a9c81d5e..29b090bbffe 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -70,7 +70,7 @@ func Test_HeadListener_HappyPath(t *testing.T) { done := func() { doneAwaiter.ItHappened() } - go hl.ListenForNewHeads(handler, done) + go hl.ListenForNewHeads(func() {}, handler, done) subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t)) require.Eventually(t, hl.Connected, tests.WaitTimeout(t), tests.TestInterval) @@ -129,7 +129,7 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) { done := func() { doneAwaiter.ItHappened() } - go hl.ListenForNewHeads(handler, done) + go hl.ListenForNewHeads(func() {}, handler, done) subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t)) @@ -190,7 +190,7 @@ func Test_HeadListener_SubscriptionErr(t *testing.T) { subscribeAwaiter.ItHappened() }) go func() { - hl.ListenForNewHeads(hnh, done) + hl.ListenForNewHeads(func() {}, hnh, done) }() // Put a head on the channel to ensure we test all code paths diff --git a/core/chains/evm/headtracker/head_saver_test.go b/core/chains/evm/headtracker/head_saver_test.go index 9be9f838d08..43e79235e90 100644 --- a/core/chains/evm/headtracker/head_saver_test.go +++ b/core/chains/evm/headtracker/head_saver_test.go @@ -47,6 +47,7 @@ type config struct { finalityDepth uint32 blockEmissionIdleWarningThreshold time.Duration finalityTagEnabled bool + finalizedBlockOffset uint32 } func (c *config) FinalityDepth() uint32 { return c.finalityDepth } @@ -58,6 +59,10 @@ func (c *config) FinalityTagEnabled() bool { return c.finalityTagEnabled } +func (c *config) FinalizedBlockOffset() uint32 { + return c.finalizedBlockOffset +} + type saverOpts struct { headTrackerConfig *headTrackerConfig } diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go index 357c4dae99a..d6c2cdc64e7 100644 --- a/core/chains/evm/headtracker/head_tracker.go +++ b/core/chains/evm/headtracker/head_tracker.go @@ -49,7 +49,10 @@ func (*nullTracker) Ready() error { return nil } func (*nullTracker) HealthReport() map[string]error { return map[string]error{} } func (*nullTracker) Name() string { return "" } func (*nullTracker) SetLogLevel(zapcore.Level) {} -func (*nullTracker) Backfill(ctx context.Context, headWithChain, latestFinalized *evmtypes.Head) (err error) { +func (*nullTracker) Backfill(ctx context.Context, headWithChain *evmtypes.Head) (err error) { return nil } func (*nullTracker) LatestChain() *evmtypes.Head { return nil } +func (*nullTracker) LatestAndFinalizedBlock(ctx context.Context) (latest, finalized *evmtypes.Head, err error) { + return nil, nil, nil +} diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 4da8d27c552..81ba3ea85f0 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -3,6 +3,7 @@ package headtracker_test import ( "context" "errors" + "fmt" "math/big" "slices" "sync" @@ -20,17 +21,19 @@ import ( "go.uber.org/zap/zaptest/observer" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/jmoiron/sqlx" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" commontypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -60,6 +63,12 @@ func TestHeadTracker_New(t *testing.T) { ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(testutils.Head(0), nil) // finalized ethClient.On("HeadByNumber", mock.Anything, big.NewInt(0)).Return(testutils.Head(0), nil) + mockEth := &testutils.MockEth{ + EthClient: ethClient, + } + ethClient.On("SubscribeNewHead", mock.Anything, mock.Anything). + Maybe(). + Return(mockEth.NewSub(t), nil) orm := headtracker.NewORM(*testutils.FixtureChainID, db) assert.Nil(t, orm.IdempotentInsertHead(tests.Context(t), testutils.Head(1))) @@ -71,9 +80,10 @@ func TestHeadTracker_New(t *testing.T) { ht := createHeadTracker(t, ethClient, evmcfg.EVM(), evmcfg.EVM().HeadTracker(), orm) ht.Start(t) - latest := ht.headSaver.LatestChain() - require.NotNil(t, latest) - assert.Equal(t, last.Number, latest.Number) + tests.AssertEventually(t, func() bool { + latest := ht.headSaver.LatestChain() + return latest != nil && last.Number == latest.Number + }) } func TestHeadTracker_MarkFinalized_MarksAndTrimsTable(t *testing.T) { @@ -126,7 +136,8 @@ func TestHeadTracker_Get(t *testing.T) { {"nil no initial", nil, nil, big.NewInt(0)}, } - for _, test := range cases { + for i := range cases { + test := cases[i] t.Run(test.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) config := testutils.NewTestChainScopedConfig(t, nil) @@ -146,9 +157,9 @@ func TestHeadTracker_Get(t *testing.T) { }, func(ctx context.Context, ch chan<- *evmtypes.Head) error { return nil }, ) - ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(testutils.Head(0), nil) + ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(testutils.Head(0), nil).Maybe() - fnCall := ethClient.On("HeadByNumber", mock.Anything, mock.Anything) + fnCall := ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Maybe() fnCall.RunFn = func(args mock.Arguments) { num := args.Get(1).(*big.Int) fnCall.ReturnArguments = mock.Arguments{testutils.Head(num.Int64()), nil} @@ -166,7 +177,10 @@ func TestHeadTracker_Get(t *testing.T) { assert.NoError(t, err) } - assert.Equal(t, test.want, ht.headSaver.LatestChain().ToInt()) + tests.AssertEventually(t, func() bool { + latest := ht.headSaver.LatestChain().ToInt() + return latest != nil && test.want.Cmp(latest) == 0 + }) }) } } @@ -226,19 +240,12 @@ func TestHeadTracker_Start(t *testing.T) { } }) orm := headtracker.NewORM(*testutils.FixtureChainID, db) - ethClient := testutils.NewEthClientMockWithDefaultChain(t) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + mockEth := &testutils.MockEth{EthClient: ethClient} + sub := mockEth.NewSub(t) + ethClient.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Maybe() return createHeadTracker(t, ethClient, config.EVM(), config.EVM().HeadTracker(), orm) } - - t.Run("Fail start if context was canceled", func(t *testing.T) { - ctx, cancel := context.WithCancel(tests.Context(t)) - ht := newHeadTracker(t, opts{}) - ht.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Run(func(args mock.Arguments) { - cancel() - }).Return(testutils.Head(0), context.Canceled) - err := ht.headTracker.Start(ctx) - require.ErrorIs(t, err, context.Canceled) - }) t.Run("Starts even if failed to get initialHead", func(t *testing.T) { ht := newHeadTracker(t, opts{}) ht.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(testutils.Head(0), errors.New("failed to get init head")) @@ -268,20 +275,6 @@ func TestHeadTracker_Start(t *testing.T) { ht.Start(t) tests.AssertLogEventually(t, ht.observer, "Error handling initial head") }) - t.Run("Logs error if finality gap is too big", func(t *testing.T) { - ht := newHeadTracker(t, opts{FinalityTagEnable: ptr(true), FinalityTagBypass: ptr(false), MaxAllowedFinalityDepth: ptr(uint32(10))}) - head := testutils.Head(1000) - ht.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(head, nil).Once() - ht.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(testutils.Head(989), nil).Once() - ht.ethClient.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(nil, errors.New("failed to connect")).Maybe() - ht.Start(t) - tests.AssertEventually(t, func() bool { - // must exactly match the error passed to logger - field := zap.String("err", "failed to calculate latest finalized head: gap between latest finalized block (989) and current head (1000) is too large (> 10)") - filtered := ht.observer.FilterMessage("Error handling initial head").FilterField(field) - return filtered.Len() > 0 - }) - }) t.Run("Happy path (finality tag)", func(t *testing.T) { head := testutils.Head(1000) ht := newHeadTracker(t, opts{FinalityTagEnable: ptr(true), FinalityTagBypass: ptr(false)}) @@ -877,10 +870,23 @@ func TestHeadTracker_Backfill(t *testing.T) { ctx := tests.Context(t) type opts struct { - Heads []evmtypes.Head + Heads []evmtypes.Head + FinalityTagEnabled bool + FinalizedBlockOffset uint32 + FinalityDepth uint32 + MaxAllowedFinalityDepth uint32 } newHeadTrackerUniverse := func(t *testing.T, opts opts) *headTrackerUniverse { - evmcfg := testutils.NewTestChainScopedConfig(t, nil) + evmcfg := testutils.NewTestChainScopedConfig(t, func(c *toml.EVMConfig) { + c.FinalityTagEnabled = ptr(opts.FinalityTagEnabled) + c.FinalizedBlockOffset = ptr(opts.FinalizedBlockOffset) + c.FinalityDepth = ptr(opts.FinalityDepth) + c.HeadTracker.FinalityTagBypass = ptr(false) + if opts.MaxAllowedFinalityDepth > 0 { + c.HeadTracker.MaxAllowedFinalityDepth = ptr(opts.MaxAllowedFinalityDepth) + } + }) + db := pgtest.NewSqlxDB(t) orm := headtracker.NewORM(*testutils.FixtureChainID, db) for i := range opts.Heads { @@ -894,26 +900,44 @@ func TestHeadTracker_Backfill(t *testing.T) { return ht } + t.Run("returns error if failed to get latestFinalized block", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + const expectedError = "failed to fetch latest finalized block" + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(nil, errors.New(expectedError)).Once() + + err := htu.headTracker.Backfill(ctx, &h12) + require.ErrorContains(t, err, expectedError) + }) t.Run("returns error if latestFinalized is not valid", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{}) + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(nil, nil).Once() + + err := htu.headTracker.Backfill(ctx, &h12) + require.EqualError(t, err, "failed to calculate finalized block: failed to get valid latest finalized block") + }) + t.Run("Returns error if finality gap is too big", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true, MaxAllowedFinalityDepth: 2}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h9, nil).Once() - err := htu.headTracker.Backfill(ctx, &h12, nil) - require.EqualError(t, err, "can not perform backfill without a valid latestFinalized head") + err := htu.headTracker.Backfill(ctx, &h12) + require.EqualError(t, err, "gap between latest finalized block (9) and current head (12) is too large (> 2)") }) t.Run("Returns error if finalized head is ahead of canonical", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{}) + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h14Orphaned, nil).Once() - err := htu.headTracker.Backfill(ctx, &h12, &h14Orphaned) + err := htu.headTracker.Backfill(ctx, &h12) require.EqualError(t, err, "invariant violation: expected head of canonical chain to be ahead of the latestFinalized") }) t.Run("Returns error if finalizedHead is not present in the canonical chain", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h14Orphaned, nil).Once() - err := htu.headTracker.Backfill(ctx, &h15, &h14Orphaned) + err := htu.headTracker.Backfill(ctx, &h15) require.EqualError(t, err, "expected finalized block to be present in canonical chain") }) t.Run("Marks all blocks in chain that are older than finalized", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) assertFinalized := func(expectedFinalized bool, msg string, heads ...evmtypes.Head) { for _, h := range heads { @@ -922,18 +946,20 @@ func TestHeadTracker_Backfill(t *testing.T) { } } - err := htu.headTracker.Backfill(ctx, &h15, &h14) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h14, nil).Once() + err := htu.headTracker.Backfill(ctx, &h15) require.NoError(t, err) assertFinalized(true, "expected heads to be marked as finalized after backfill", h14, h13, h12, h11) assertFinalized(false, "expected heads to remain unfinalized", h15, head10) }) t.Run("fetches a missing head", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h9, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil) - err := htu.headTracker.Backfill(ctx, &h12, &h9) + err := htu.headTracker.Backfill(ctx, &h12) require.NoError(t, err) h := htu.headSaver.Chain(h12.Hash) @@ -950,16 +976,16 @@ func TestHeadTracker_Backfill(t *testing.T) { require.NoError(t, err) assert.Equal(t, int64(10), writtenHead.Number) }) - t.Run("fetches only heads that are missing", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&head8, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil) htu.ethClient.On("HeadByHash", mock.Anything, head8.Hash). Return(&head8, nil) - err := htu.headTracker.Backfill(ctx, &h15, &head8) + err := htu.headTracker.Backfill(ctx, &h15) require.NoError(t, err) h := htu.headSaver.Chain(h15.Hash) @@ -971,7 +997,8 @@ func TestHeadTracker_Backfill(t *testing.T) { }) t.Run("abandons backfill and returns error if the eth node returns not found", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&head8, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil). Once() @@ -979,9 +1006,9 @@ func TestHeadTracker_Backfill(t *testing.T) { Return(nil, ethereum.NotFound). Once() - err := htu.headTracker.Backfill(ctx, &h12, &head8) + err := htu.headTracker.Backfill(ctx, &h12) require.Error(t, err) - require.EqualError(t, err, "fetchAndSaveHead failed: not found") + require.ErrorContains(t, err, "fetchAndSaveHead failed: not found") h := htu.headSaver.Chain(h12.Hash) @@ -991,7 +1018,8 @@ func TestHeadTracker_Backfill(t *testing.T) { }) t.Run("abandons backfill and returns error if the context time budget is exceeded", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: heads}) + htu := newHeadTrackerUniverse(t, opts{Heads: heads, FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&head8, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, head10.Hash). Return(&head10, nil) lctx, cancel := context.WithCancel(ctx) @@ -1000,9 +1028,9 @@ func TestHeadTracker_Backfill(t *testing.T) { cancel() }) - err := htu.headTracker.Backfill(lctx, &h12, &head8) + err := htu.headTracker.Backfill(lctx, &h12) require.Error(t, err) - require.EqualError(t, err, "fetchAndSaveHead failed: context canceled") + require.ErrorContains(t, err, "fetchAndSaveHead failed: context canceled") h := htu.headSaver.Chain(h12.Hash) @@ -1010,17 +1038,17 @@ func TestHeadTracker_Backfill(t *testing.T) { assert.Equal(t, 4, int(h.ChainLength())) assert.Equal(t, int64(9), h.EarliestInChain().BlockNumber()) }) - t.Run("abandons backfill and returns error when fetching a block by hash fails, indicating a reorg", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{}) + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h11, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, h14.Hash).Return(&h14, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, h13.Hash).Return(&h13, nil).Once() htu.ethClient.On("HeadByHash", mock.Anything, h12.Hash).Return(nil, errors.New("not found")).Once() - err := htu.headTracker.Backfill(ctx, &h15, &h11) + err := htu.headTracker.Backfill(ctx, &h15) require.Error(t, err) - require.EqualError(t, err, "fetchAndSaveHead failed: not found") + require.ErrorContains(t, err, "fetchAndSaveHead failed: not found") h := htu.headSaver.Chain(h14.Hash) @@ -1029,9 +1057,10 @@ func TestHeadTracker_Backfill(t *testing.T) { assert.Equal(t, int64(13), h.EarliestInChain().BlockNumber()) }) t.Run("marks head as finalized, if latestHead = finalizedHead (0 finality depth)", func(t *testing.T) { - htu := newHeadTrackerUniverse(t, opts{Heads: []evmtypes.Head{h15}}) + htu := newHeadTrackerUniverse(t, opts{Heads: []evmtypes.Head{h15}, FinalityTagEnabled: true}) finalizedH15 := h15 // copy h15 to have different addresses - err := htu.headTracker.Backfill(ctx, &h15, &finalizedH15) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&finalizedH15, nil).Once() + err := htu.headTracker.Backfill(ctx, &h15) require.NoError(t, err) h := htu.headSaver.LatestChain() @@ -1042,12 +1071,215 @@ func TestHeadTracker_Backfill(t *testing.T) { assert.Equal(t, h15.BlockNumber(), h.BlockNumber()) assert.Equal(t, h15.Hash, h.Hash) }) + t.Run("marks block as finalized according to FinalizedBlockOffset (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{Heads: []evmtypes.Head{h15}, FinalityTagEnabled: true, FinalizedBlockOffset: 2}) + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&h14, nil).Once() + // calculateLatestFinalizedBlock fetches blocks at LatestFinalized - FinalizedBlockOffset + htu.ethClient.On("HeadByNumber", mock.Anything, big.NewInt(h12.Number)).Return(&h12, nil).Once() + // backfill from 15 to 12 + htu.ethClient.On("HeadByHash", mock.Anything, h12.Hash).Return(&h12, nil).Once() + htu.ethClient.On("HeadByHash", mock.Anything, h13.Hash).Return(&h13, nil).Once() + htu.ethClient.On("HeadByHash", mock.Anything, h14.Hash).Return(&h14, nil).Once() + err := htu.headTracker.Backfill(ctx, &h15) + require.NoError(t, err) + + h := htu.headSaver.LatestChain() + // h - must contain 15, 14, 13, 12 and only 12 is finalized + assert.Equal(t, 4, int(h.ChainLength())) + for ; h.Hash != h12.Hash; h = h.Parent { + assert.False(t, h.IsFinalized) + } + + assert.True(t, h.IsFinalized) + assert.Equal(t, h12.BlockNumber(), h.BlockNumber()) + assert.Equal(t, h12.Hash, h.Hash) + }) + t.Run("marks block as finalized according to FinalizedBlockOffset (finality depth)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{Heads: []evmtypes.Head{h15}, FinalityDepth: 1, FinalizedBlockOffset: 2}) + htu.ethClient.On("HeadByNumber", mock.Anything, big.NewInt(12)).Return(&h12, nil).Once() + + // backfill from 15 to 12 + htu.ethClient.On("HeadByHash", mock.Anything, h14.Hash).Return(&h14, nil).Once() + htu.ethClient.On("HeadByHash", mock.Anything, h13.Hash).Return(&h13, nil).Once() + htu.ethClient.On("HeadByHash", mock.Anything, h12.Hash).Return(&h12, nil).Once() + err := htu.headTracker.Backfill(ctx, &h15) + require.NoError(t, err) + + h := htu.headSaver.LatestChain() + // h - must contain 15, 14, 13, 12 and only 12 is finalized + assert.Equal(t, 4, int(h.ChainLength())) + for ; h.Hash != h12.Hash; h = h.Parent { + assert.False(t, h.IsFinalized) + } + + assert.True(t, h.IsFinalized) + assert.Equal(t, h12.BlockNumber(), h.BlockNumber()) + assert.Equal(t, h12.Hash, h.Hash) + }) + t.Run("marks block as finalized according to FinalizedBlockOffset even with instant finality", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{Heads: []evmtypes.Head{h15}, FinalityDepth: 0, FinalizedBlockOffset: 2}) + htu.ethClient.On("HeadByNumber", mock.Anything, big.NewInt(13)).Return(&h13, nil).Once() + + // backfill from 15 to 13 + htu.ethClient.On("HeadByHash", mock.Anything, h14.Hash).Return(&h14, nil).Once() + htu.ethClient.On("HeadByHash", mock.Anything, h13.Hash).Return(&h13, nil).Once() + err := htu.headTracker.Backfill(ctx, &h15) + require.NoError(t, err) + + h := htu.headSaver.LatestChain() + // h - must contain 15, 14, 13, only 13 is finalized + assert.Equal(t, 3, int(h.ChainLength())) + for ; h.Hash != h13.Hash; h = h.Parent { + assert.False(t, h.IsFinalized) + } + + assert.True(t, h.IsFinalized) + assert.Equal(t, h13.BlockNumber(), h.BlockNumber()) + assert.Equal(t, h13.Hash, h.Hash) + }) +} + +func TestHeadTracker_LatestAndFinalizedBlock(t *testing.T) { + t.Parallel() + + ctx := tests.Context(t) + + h11 := testutils.Head(11) + h11.ParentHash = utils.NewHash() + + h12 := testutils.Head(12) + h12.ParentHash = h11.Hash + + h13 := testutils.Head(13) + h13.ParentHash = h12.Hash + + type opts struct { + Heads []evmtypes.Head + FinalityTagEnabled bool + FinalizedBlockOffset uint32 + FinalityDepth uint32 + } + + newHeadTrackerUniverse := func(t *testing.T, opts opts) *headTrackerUniverse { + evmcfg := testutils.NewTestChainScopedConfig(t, func(c *toml.EVMConfig) { + c.FinalityTagEnabled = ptr(opts.FinalityTagEnabled) + c.FinalizedBlockOffset = ptr(opts.FinalizedBlockOffset) + c.FinalityDepth = ptr(opts.FinalityDepth) + }) + + db := pgtest.NewSqlxDB(t) + orm := headtracker.NewORM(*testutils.FixtureChainID, db) + for i := range opts.Heads { + require.NoError(t, orm.IdempotentInsertHead(tests.Context(t), &opts.Heads[i])) + } + ethClient := evmtest.NewEthClientMock(t) + ethClient.On("ConfiguredChainID", mock.Anything).Return(testutils.FixtureChainID, nil) + ht := createHeadTracker(t, ethClient, evmcfg.EVM(), evmcfg.EVM().HeadTracker(), orm) + _, err := ht.headSaver.Load(tests.Context(t), 0) + require.NoError(t, err) + return ht + } + t.Run("returns error if failed to get latest block", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + const expectedError = "failed to fetch latest block" + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, errors.New(expectedError)).Once() + + _, _, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.ErrorContains(t, err, expectedError) + }) + t.Run("returns error if latest block is invalid", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil).Once() + + _, _, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.ErrorContains(t, err, "expected latest block to be valid") + }) + t.Run("returns error if failed to get latest finalized (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + const expectedError = "failed to get latest finalized block" + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(nil, fmt.Errorf(expectedError)).Once() + + _, _, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.ErrorContains(t, err, expectedError) + }) + t.Run("returns error if latest finalized block is not valid (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(nil, nil).Once() + + _, _, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.ErrorContains(t, err, "failed to get valid latest finalized block") + }) + t.Run("returns latest finalized block as is if FinalizedBlockOffset is 0 (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(h11, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL, h13) + assert.Equal(t, actualLF, h11) + }) + t.Run("returns latest finalized block with offset from cache (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true, FinalizedBlockOffset: 1, Heads: []evmtypes.Head{*h13, *h12, *h11}}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(h12, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL.Number, h13.Number) + assert.Equal(t, actualLF.Number, h11.Number) + }) + t.Run("returns latest finalized block with offset from RPC (finality tag)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityTagEnabled: true, FinalizedBlockOffset: 2, Heads: []evmtypes.Head{*h13, *h12, *h11}}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + htu.ethClient.On("LatestFinalizedBlock", mock.Anything).Return(h12, nil).Once() + h10 := testutils.Head(10) + htu.ethClient.On("HeadByNumber", mock.Anything, big.NewInt(10)).Return(h10, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL.Number, h13.Number) + assert.Equal(t, actualLF.Number, h10.Number) + }) + t.Run("returns current head for both latest and finalized for FD = 0 (finality depth)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL.Number, h13.Number) + assert.Equal(t, actualLF.Number, h13.Number) + }) + t.Run("returns latest finalized block with offset from cache (finality depth)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityDepth: 1, FinalizedBlockOffset: 1, Heads: []evmtypes.Head{*h13, *h12, *h11}}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL.Number, h13.Number) + assert.Equal(t, actualLF.Number, h11.Number) + }) + t.Run("returns latest finalized block with offset from RPC (finality depth)", func(t *testing.T) { + htu := newHeadTrackerUniverse(t, opts{FinalityDepth: 1, FinalizedBlockOffset: 2, Heads: []evmtypes.Head{*h13, *h12, *h11}}) + htu.ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h13, nil).Once() + h10 := testutils.Head(10) + htu.ethClient.On("HeadByNumber", mock.Anything, big.NewInt(10)).Return(h10, nil).Once() + + actualL, actualLF, err := htu.headTracker.LatestAndFinalizedBlock(ctx) + require.NoError(t, err) + assert.Equal(t, actualL.Number, h13.Number) + assert.Equal(t, actualLF.Number, h10.Number) + }) } // BenchmarkHeadTracker_Backfill - benchmarks HeadTracker's Backfill with focus on efficiency after initial // backfill on start up func BenchmarkHeadTracker_Backfill(b *testing.B) { - evmcfg := testutils.NewTestChainScopedConfig(b, nil) + evmcfg := testutils.NewTestChainScopedConfig(b, func(c *toml.EVMConfig) { + c.FinalityTagEnabled = ptr(true) + }) db := pgtest.NewSqlxDB(b) chainID := big.NewInt(evmclient.NullClientChainID) orm := headtracker.NewORM(*chainID, db) @@ -1068,15 +1300,17 @@ func BenchmarkHeadTracker_Backfill(b *testing.B) { number := hash.Big().Int64() return makeBlock(number), nil }) + ethClient.On("LatestFinalizedBlock", mock.Anything).Return(finalized, nil).Once() // run initial backfill to populate the database - err := ht.headTracker.Backfill(ctx, latest, finalized) + err := ht.headTracker.Backfill(ctx, latest) require.NoError(b, err) b.ResetTimer() // focus benchmark on processing of a new latest block for i := 0; i < b.N; i++ { latest = makeBlock(int64(finalityDepth + i)) finalized = makeBlock(int64(i + 1)) - err := ht.headTracker.Backfill(ctx, latest, finalized) + ethClient.On("LatestFinalizedBlock", mock.Anything).Return(finalized, nil).Once() + err := ht.headTracker.Backfill(ctx, latest) require.NoError(b, err) } } @@ -1129,8 +1363,8 @@ type headTrackerUniverse struct { ethClient *evmclimocks.Client } -func (u *headTrackerUniverse) Backfill(ctx context.Context, head, finalizedHead *evmtypes.Head) error { - return u.headTracker.Backfill(ctx, head, finalizedHead) +func (u *headTrackerUniverse) Backfill(ctx context.Context, head *evmtypes.Head) error { + return u.headTracker.Backfill(ctx, head) } func (u *headTrackerUniverse) Start(t *testing.T) { diff --git a/core/chains/evm/headtracker/simulated_head_tracker.go b/core/chains/evm/headtracker/simulated_head_tracker.go new file mode 100644 index 00000000000..e1e550de992 --- /dev/null +++ b/core/chains/evm/headtracker/simulated_head_tracker.go @@ -0,0 +1,53 @@ +package headtracker + +import ( + "context" + "fmt" + "math/big" + + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" +) + +// simulatedHeadTracker - simplified version of HeadTracker that works with simulated backed +type simulatedHeadTracker struct { + ec evmclient.Client + useFinalityTag bool + finalityDepth int64 +} + +func NewSimulatedHeadTracker(ec evmclient.Client, useFinalityTag bool, finalityDepth int64) *simulatedHeadTracker { + return &simulatedHeadTracker{ + ec: ec, + useFinalityTag: useFinalityTag, + finalityDepth: finalityDepth, + } +} + +func (ht *simulatedHeadTracker) LatestAndFinalizedBlock(ctx context.Context) (*evmtypes.Head, *evmtypes.Head, error) { + latest, err := ht.ec.HeadByNumber(ctx, nil) + if err != nil { + return nil, nil, err + } + + if latest == nil { + return nil, nil, fmt.Errorf("expected latest block to be valid") + } + + var finalizedBlock *evmtypes.Head + if ht.useFinalityTag { + finalizedBlock, err = ht.ec.LatestFinalizedBlock(ctx) + } else { + finalizedBlock, err = ht.ec.HeadByNumber(ctx, big.NewInt(max(latest.Number-ht.finalityDepth, 0))) + } + + if err != nil { + return nil, nil, fmt.Errorf("simulatedHeadTracker failed to get finalized block") + } + + if finalizedBlock == nil { + return nil, nil, fmt.Errorf("expected finalized block to be valid") + } + + return latest, finalizedBlock, nil +} diff --git a/core/chains/evm/keystore/mocks/eth.go b/core/chains/evm/keystore/mocks/eth.go index 9c11551e2c2..df46adb2022 100644 --- a/core/chains/evm/keystore/mocks/eth.go +++ b/core/chains/evm/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/mocks/abigen_contract.go b/core/chains/evm/log/mocks/abigen_contract.go index 3ab5e350505..31e268cd859 100644 --- a/core/chains/evm/log/mocks/abigen_contract.go +++ b/core/chains/evm/log/mocks/abigen_contract.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/mocks/broadcast.go b/core/chains/evm/log/mocks/broadcast.go index 1f1817474ec..c7dfb90055a 100644 --- a/core/chains/evm/log/mocks/broadcast.go +++ b/core/chains/evm/log/mocks/broadcast.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index 221456c508b..4571ba4babf 100644 --- a/core/chains/evm/log/mocks/broadcaster.go +++ b/core/chains/evm/log/mocks/broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/logpoller/helper_test.go b/core/chains/evm/logpoller/helper_test.go index d79fd9e151c..eefc0bae543 100644 --- a/core/chains/evm/logpoller/helper_test.go +++ b/core/chains/evm/logpoller/helper_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" @@ -67,10 +68,11 @@ func SetupTH(t testing.TB, opts logpoller.Opts) TestHarness { esc := client.NewSimulatedBackendClient(t, backend, chainID) + headTracker := headtracker.NewSimulatedHeadTracker(esc, opts.UseFinalityTag, opts.FinalityDepth) if opts.PollPeriod == 0 { opts.PollPeriod = 1 * time.Hour } - lp := logpoller.NewLogPoller(o, esc, lggr, opts) + lp := logpoller.NewLogPoller(o, esc, lggr, headTracker, opts) emitterAddress1, _, emitter1, err := log_emitter.DeployLogEmitter(owner, backend.Client()) require.NoError(t, err) emitterAddress2, _, emitter2, err := log_emitter.DeployLogEmitter(owner, backend.Client()) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index b33a7f88fff..459aa592c02 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -89,6 +89,10 @@ type Client interface { ConfiguredChainID() *big.Int } +type HeadTracker interface { + LatestAndFinalizedBlock(ctx context.Context) (latest, finalized *evmtypes.Head, err error) +} + var ( _ LogPollerTest = &logPoller{} ErrReplayRequestAborted = pkgerrors.New("aborted, replay request cancelled") @@ -101,6 +105,7 @@ type logPoller struct { services.StateMachine ec Client orm ORM + headTracker HeadTracker lggr logger.SugaredLogger pollPeriod time.Duration // poll period set by block production rate useFinalityTag bool // indicates whether logPoller should use chain's finality or pick a fixed depth for finality @@ -151,11 +156,12 @@ type Opts struct { // // How fast that can be done depends largely on network speed and DB, but even for the fastest // support chain, polygon, which has 2s block times, we need RPCs roughly with <= 500ms latency -func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, opts Opts) *logPoller { +func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, headTracker HeadTracker, opts Opts) *logPoller { return &logPoller{ stopCh: make(chan struct{}), ec: ec, orm: orm, + headTracker: headTracker, lggr: logger.Sugared(logger.Named(lggr, "LogPoller")), replayStart: make(chan int64), replayComplete: make(chan error), @@ -553,9 +559,14 @@ func (lp *logPoller) run() { defer lp.wg.Done() ctx, cancel := lp.stopCh.NewCtx() defer cancel() - logPollTick := time.After(0) + logPollTicker := services.NewTicker(lp.pollPeriod) + defer logPollTicker.Stop() // stagger these somewhat, so they don't all run back-to-back - backupLogPollTick := time.After(100 * time.Millisecond) + backupLogPollTicker := services.TickerConfig{ + Initial: 100 * time.Millisecond, + JitterPct: services.DefaultJitter, + }.NewTicker(time.Duration(lp.backupPollerBlockDelay) * lp.pollPeriod) + defer backupLogPollTicker.Stop() filtersLoaded := false for { @@ -564,8 +575,7 @@ func (lp *logPoller) run() { return case fromBlockReq := <-lp.replayStart: lp.handleReplayRequest(ctx, fromBlockReq, filtersLoaded) - case <-logPollTick: - logPollTick = time.After(utils.WithJitter(lp.pollPeriod)) + case <-logPollTicker.C: if !filtersLoaded { if err := lp.loadFilters(ctx); err != nil { lp.lggr.Errorw("Failed loading filters in main logpoller loop, retrying later", "err", err) @@ -603,7 +613,7 @@ func (lp *logPoller) run() { start = lastProcessed.BlockNumber + 1 } lp.PollAndSaveLogs(ctx, start) - case <-backupLogPollTick: + case <-backupLogPollTicker.C: if lp.backupPollerBlockDelay == 0 { continue // backup poller is disabled } @@ -615,7 +625,6 @@ func (lp *logPoller) run() { // frequently than the primary log poller (instead of roughly once per block it runs once roughly once every // lp.backupPollerDelay blocks--with default settings about 100x less frequently). - backupLogPollTick = time.After(utils.WithJitter(time.Duration(lp.backupPollerBlockDelay) * lp.pollPeriod)) if !filtersLoaded { lp.lggr.Warnw("Backup log poller ran before filters loaded, skipping") continue @@ -1008,38 +1017,15 @@ func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int } } -// Returns information about latestBlock, latestFinalizedBlockNumber -// If finality tag is not enabled, latestFinalizedBlockNumber is calculated as latestBlockNumber - lp.finalityDepth (configured param) -// Otherwise, we return last finalized block number returned from chain +// Returns information about latestBlock, latestFinalizedBlockNumber provided by HeadTracker func (lp *logPoller) latestBlocks(ctx context.Context) (*evmtypes.Head, int64, error) { - // If finality is not enabled, we can only fetch the latest block - if !lp.useFinalityTag { - // Example: - // finalityDepth = 2 - // Blocks: 1->2->3->4->5(latestBlock) - // latestFinalizedBlockNumber would be 3 - latestBlock, err := lp.ec.HeadByNumber(ctx, nil) - if err != nil { - return nil, 0, err - } - if latestBlock == nil { - // Shouldn't happen with a real client, but still better rather to - // return error than panic - return nil, 0, errors.New("latest block is nil") - } - // If chain has fewer blocks than finalityDepth, return 0 - return latestBlock, mathutil.Max(latestBlock.Number-lp.finalityDepth, 0), nil - } - - // If finality is enabled, we need to get the latest and finalized blocks. - blocks, err := lp.batchFetchBlocks(ctx, []string{rpc.LatestBlockNumber.String(), rpc.FinalizedBlockNumber.String()}, 2) + latest, finalized, err := lp.headTracker.LatestAndFinalizedBlock(ctx) if err != nil { - return nil, 0, err + return nil, 0, fmt.Errorf("failed to get latest and latest finalized block from HeadTracker: %w", err) } - 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 + + lp.lggr.Debugw("Latest blocks read from chain", "latest", latest.Number, "finalized", finalized.BlockNumber()) + return latest, finalized.BlockNumber(), nil } // Find the first place where our chain and their chain have the same block, diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index bc295105874..448710b93f3 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math/big" - "reflect" "strings" "sync" "testing" @@ -22,10 +21,13 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + htMocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -73,7 +75,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := NewLogPoller(orm, nil, lggr, lpOpts) + lp := NewLogPoller(orm, nil, lggr, nil, lpOpts) // We expect a zero Filter if nothing registered yet. f := lp.Filter(nil, nil, nil) @@ -208,8 +210,10 @@ func TestLogPoller_BackupPollerStartup(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := NewORM(chainID, db, lggr) latestBlock := int64(4) + const finalityDepth = 2 - head := evmtypes.Head{Number: latestBlock} + head := &evmtypes.Head{Number: latestBlock} + finalizedHead := &evmtypes.Head{Number: latestBlock - finalityDepth} events := []common.Hash{EmitterABI.Events["Log1"].ID} log1 := types.Log{ Index: 0, @@ -222,20 +226,22 @@ func TestLogPoller_BackupPollerStartup(t *testing.T) { } ec := evmclimocks.NewClient(t) - ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil) ec.On("ConfiguredChainID").Return(chainID, nil) + headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(head, finalizedHead, nil) + ctx := testutils.Context(t) lpOpts := Opts{ PollPeriod: time.Hour, - FinalityDepth: 2, + FinalityDepth: finalityDepth, BackfillBatchSize: 3, RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, BackupPollerBlockDelay: 0, } - lp := NewLogPoller(orm, ec, lggr, lpOpts) + lp := NewLogPoller(orm, ec, lggr, headTracker, lpOpts) lp.BackupPollAndSaveLogs(ctx) assert.Equal(t, int64(0), lp.backupPollerNextBlock) assert.Equal(t, 1, observedLogs.FilterMessageSnippet("ran before first successful log poller run").Len()) @@ -309,7 +315,14 @@ func TestLogPoller_Replay(t *testing.T) { KeepFinalizedBlocksDepth: 20, BackupPollerBlockDelay: 0, } - lp := NewLogPoller(orm, ec, lggr, lpOpts) + headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(func(ctx context.Context) (*evmtypes.Head, *evmtypes.Head, error) { + headCopy := head + finalized := &evmtypes.Head{Number: headCopy.Number - lpOpts.FinalityDepth} + return &headCopy, finalized, nil + }) + lp := NewLogPoller(orm, ec, lggr, headTracker, lpOpts) { ctx := testutils.Context(t) @@ -533,10 +546,6 @@ func (lp *logPoller) reset() { func Test_latestBlockAndFinalityDepth(t *testing.T) { lggr := logger.Test(t) - chainID := testutils.FixtureChainID - db := pgtest.NewSqlxDB(t) - orm := NewORM(chainID, db, lggr) - ctx := testutils.Context(t) lpOpts := Opts{ PollPeriod: time.Hour, @@ -545,71 +554,27 @@ func Test_latestBlockAndFinalityDepth(t *testing.T) { KeepFinalizedBlocksDepth: 20, } - t.Run("pick latest block from chain and use finality from config with finality disabled", func(t *testing.T) { - head := evmtypes.Head{Number: 4} - - lpOpts.UseFinalityTag = false - lpOpts.FinalityDepth = int64(3) - ec := evmclimocks.NewClient(t) - ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) + t.Run("headTracker returns an error", func(t *testing.T) { + headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + const expectedError = "finalized block is not available yet" + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(&evmtypes.Head{}, &evmtypes.Head{}, fmt.Errorf(expectedError)) - lp := NewLogPoller(orm, ec, lggr, lpOpts) - latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(ctx) - require.NoError(t, err) - require.Equal(t, latestBlock.Number, head.Number) - require.Equal(t, lpOpts.FinalityDepth, latestBlock.Number-lastFinalizedBlockNumber) + lp := NewLogPoller(nil, nil, lggr, headTracker, lpOpts) + _, _, err := lp.latestBlocks(tests.Context(t)) + require.ErrorContains(t, err, expectedError) }) - - t.Run("finality tags in use", func(t *testing.T) { - t.Run("client returns data properly", func(t *testing.T) { - expectedLatestBlockNumber := int64(20) - expectedLastFinalizedBlockNumber := int64(12) - ec := evmclimocks.NewClient(t) - ec.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { - return len(b) == 2 && - reflect.DeepEqual(b[0].Args, []interface{}{"latest", false}) && - reflect.DeepEqual(b[1].Args, []interface{}{"finalized", false}) - })).Return(nil).Run(func(args mock.Arguments) { - elems := args.Get(1).([]rpc.BatchElem) - // Latest block details - *(elems[0].Result.(*evmtypes.Head)) = evmtypes.Head{Number: expectedLatestBlockNumber, Hash: utils.RandomBytes32()} - // Finalized block details - *(elems[1].Result.(*evmtypes.Head)) = evmtypes.Head{Number: expectedLastFinalizedBlockNumber, Hash: utils.RandomBytes32()} - }) - - lpOpts.UseFinalityTag = true - lp := NewLogPoller(orm, ec, lggr, lpOpts) - - latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(ctx) - require.NoError(t, err) - require.Equal(t, expectedLatestBlockNumber, latestBlock.Number) - require.Equal(t, expectedLastFinalizedBlockNumber, lastFinalizedBlockNumber) - }) - - t.Run("client returns error for at least one of the calls", func(t *testing.T) { - ec := evmclimocks.NewClient(t) - ec.On("BatchCallContext", mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - elems := args.Get(1).([]rpc.BatchElem) - // Latest block details - *(elems[0].Result.(*evmtypes.Head)) = evmtypes.Head{Number: 10} - // Finalized block details - elems[1].Error = fmt.Errorf("some error") - }) - - lpOpts.UseFinalityTag = true - lp := NewLogPoller(orm, ec, lggr, lpOpts) - _, _, err := lp.latestBlocks(ctx) - require.Error(t, err) - }) - - t.Run("BatchCall returns an error", func(t *testing.T) { - ec := evmclimocks.NewClient(t) - ec.On("BatchCallContext", mock.Anything, mock.Anything).Return(fmt.Errorf("some error")) - lpOpts.UseFinalityTag = true - lp := NewLogPoller(orm, ec, lggr, lpOpts) - _, _, err := lp.latestBlocks(ctx) - require.Error(t, err) - }) + t.Run("headTracker returns valid chain", func(t *testing.T) { + headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + finalizedBlock := &evmtypes.Head{Number: 2, IsFinalized: true} + head := &evmtypes.Head{Number: 10} + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(head, finalizedBlock, nil) + + lp := NewLogPoller(nil, nil, lggr, headTracker, lpOpts) + latestBlock, finalizedBlockNumber, err := lp.latestBlocks(tests.Context(t)) + require.NoError(t, err) + require.NotNil(t, latestBlock) + assert.Equal(t, head.BlockNumber(), latestBlock.BlockNumber()) + assert.Equal(t, finalizedBlock.Number, finalizedBlockNumber) }) } @@ -653,7 +618,7 @@ func Test_FetchBlocks(t *testing.T) { errors.New("Received unfinalized block 9 while expecting finalized block (latestFinalizedBlockNumber = 5)"), }} - lp := NewLogPoller(orm, ec, lggr, lpOpts) + lp := NewLogPoller(orm, ec, lggr, nil, lpOpts) for _, tc := range cases { for _, lp.useFinalityTag = range []bool{false, true} { blockValidationReq := latestBlock @@ -693,7 +658,7 @@ func benchmarkFilter(b *testing.B, nFilters, nAddresses, nEvents int) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := NewLogPoller(nil, nil, lggr, lpOpts) + lp := NewLogPoller(nil, nil, lggr, nil, lpOpts) for i := 0; i < nFilters; i++ { var addresses []common.Address var events []common.Hash diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 77502c97ff7..cdaf0d89062 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -26,7 +26,9 @@ import ( commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype" + htMocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -708,7 +710,9 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(orm, client.NewSimulatedBackendClient(t, backend, chainID), lggr, lpOpts) + simulatedClient := client.NewSimulatedBackendClient(t, backend, chainID) + ht := headtracker.NewSimulatedHeadTracker(simulatedClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(orm, simulatedClient, lggr, ht, lpOpts) for i := 0; i < finalityDepth; i++ { // Have enough blocks that we could reorg the full finalityDepth-1. backend.Commit() } @@ -1481,7 +1485,7 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(o, client.NewSimulatedBackendClient(t, backend, chainID2), lggr, lpOpts) + lp := logpoller.NewLogPoller(o, client.NewSimulatedBackendClient(t, backend, chainID2), lggr, nil, lpOpts) err = lp.Replay(ctx, 5) // block number too high require.ErrorContains(t, err, "Invalid replay block number") @@ -1536,7 +1540,8 @@ func TestTooManyLogResults(t *testing.T) { RpcBatchSize: 10, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(o, ec, lggr, lpOpts) + headTracker := htMocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + lp := logpoller.NewLogPoller(o, ec, lggr, headTracker, lpOpts) expected := []int64{10, 5, 2, 1} clientErr := client.JsonError{ @@ -1545,9 +1550,13 @@ func TestTooManyLogResults(t *testing.T) { Message: "query returned more than 10000 results. Try with this block range [0x100E698, 0x100E6D4].", } + // Simulate currentBlock = 300 + head := &evmtypes.Head{Number: 300} + finalized := &evmtypes.Head{Number: head.Number - lpOpts.FinalityDepth} + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(head, finalized, nil).Once() call1 := ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(func(ctx context.Context, blockNumber *big.Int) (*evmtypes.Head, error) { if blockNumber == nil { - return &evmtypes.Head{Number: 300}, nil // Simulate currentBlock = 300 + require.FailNow(t, "unexpected call to get current head") } return &evmtypes.Head{Number: blockNumber.Int64()}, nil }) @@ -1589,9 +1598,12 @@ func TestTooManyLogResults(t *testing.T) { // Now jump to block 500, but return error no matter how small the block range gets. // Should exit the loop with a critical error instead of hanging. + head = &evmtypes.Head{Number: 500} + finalized = &evmtypes.Head{Number: head.Number - lpOpts.FinalityDepth} + headTracker.On("LatestAndFinalizedBlock", mock.Anything).Return(head, finalized, nil).Once() call1.On("HeadByNumber", mock.Anything, mock.Anything).Return(func(ctx context.Context, blockNumber *big.Int) (*evmtypes.Head, error) { if blockNumber == nil { - return &evmtypes.Head{Number: 500}, nil // Simulate currentBlock = 300 + require.FailNow(t, "unexpected call to get current head") } return &evmtypes.Head{Number: blockNumber.Int64()}, nil }) @@ -1920,7 +1932,7 @@ func TestFindLCA(t *testing.T) { KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(orm, ec, lggr, lpOpts) + lp := logpoller.NewLogPoller(orm, ec, lggr, nil, lpOpts) t.Run("Fails, if failed to select oldest block", func(t *testing.T) { _, err := lp.FindLCA(ctx) require.ErrorContains(t, err, "failed to select the latest block") diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 3c8f445df57..76442c8e941 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index 7c55cd78ebd..2bf4898ef27 100644 --- a/core/chains/evm/mocks/balance_monitor.go +++ b/core/chains/evm/mocks/balance_monitor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index 5ec00e960ab..efaaab68afa 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 465681247e2..5a699f71bf9 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index dac0ef29cd8..40df5616c99 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -35,6 +35,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -59,7 +60,9 @@ func makeTestEvmTxm( RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, lpOpts) + + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, ht, lpOpts) // logic for building components (from evm/evm_txm.go) ------- lggr.Infow("Initializing EVM transaction manager", @@ -97,7 +100,8 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { keyStore := cltest.NewKeyStore(t, db).Eth() ethClient := testutils.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore) require.NoError(t, err) @@ -122,7 +126,8 @@ func TestTxm_CreateTransaction(t *testing.T) { ethClient := testutils.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) require.NoError(t, err) @@ -403,7 +408,8 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) ethClient := testutils.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore) require.NoError(t, err) @@ -494,7 +500,8 @@ func TestTxm_Lifecycle(t *testing.T) { keyChangeCh := make(chan struct{}) unsub := cltest.NewAwaiter() kst.On("SubscribeToKeyChanges", mock.Anything).Return(keyChangeCh, unsub.ItHappened) - estimator := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config, evmConfig.GasEstimator()) + require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst) require.NoError(t, err) @@ -549,7 +556,8 @@ func TestTxm_Reset(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, addr).Return(uint64(128), nil).Maybe() ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(44), nil).Maybe() - estimator := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM(), cfg.EVM().GasEstimator()) + require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), gcfg.Database(), gcfg.Database().Listener(), kst.Eth()) require.NoError(t, err) @@ -603,11 +611,11 @@ func TestTxm_GetTransactionStatus(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe() feeEstimator := gasmocks.NewEvmFeeEstimator(t) feeEstimator.On("Start", mock.Anything).Return(nil).Once() + feeEstimator.On("Close", mock.Anything).Return(nil).Once() feeEstimator.On("OnNewLongestChain", mock.Anything, mock.Anything).Once() txm, err := makeTestEvmTxm(t, db, ethClient, feeEstimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), gcfg.Database(), gcfg.Database().Listener(), ethKeyStore) require.NoError(t, err) - err = txm.Start(ctx) - require.NoError(t, err) + servicetest.Run(t, txm) head := &evmtypes.Head{ Hash: utils.NewHash(), diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 2af5b81ccf8..a9e5cd5841b 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -118,16 +118,23 @@ func (h *Head) IsInChain(blockHash common.Hash) bool { // HashAtHeight returns the hash of the block at the given height, if it is in the chain. // If not in chain, returns the zero hash func (h *Head) HashAtHeight(blockNum int64) common.Hash { - for { + headAtHeight, err := h.HeadAtHeight(blockNum) + if err != nil { + return common.Hash{} + } + + return headAtHeight.BlockHash() +} + +func (h *Head) HeadAtHeight(blockNum int64) (commontypes.Head[common.Hash], error) { + for h != nil { if h.Number == blockNum { - return h.Hash - } - if h.Parent == nil { - break + return h, nil } + h = h.Parent } - return common.Hash{} + return nil, fmt.Errorf("failed to find head at height %d", blockNum) } // ChainLength returns the length of the chain followed by recursively looking up parents diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index db7b876bb64..6018d68f962 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -247,6 +247,26 @@ func TestHead_EarliestInChain(t *testing.T) { assert.Equal(t, int64(1), head.EarliestInChain().BlockNumber()) } +func TestHead_HeadAtHeight(t *testing.T) { + expectedResult := &evmtypes.Head{ + Hash: common.BigToHash(big.NewInt(10)), + Number: 2, + Parent: &evmtypes.Head{ + Number: 1, + }, + } + head := evmtypes.Head{ + Number: 3, + Parent: expectedResult, + } + + headAtHeight, err := head.HeadAtHeight(2) + require.NoError(t, err) + assert.Equal(t, expectedResult, headAtHeight) + _, err = head.HeadAtHeight(0) + assert.Error(t, err, "expected to get an error if head is not in the chain") +} + func TestHead_IsInChain(t *testing.T) { hash1 := utils.NewHash() hash2 := utils.NewHash() diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 1c94e3d7dfa..b38cd2c4508 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -245,7 +245,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod LogPrunePageSize: int64(cfg.EVM().LogPrunePageSize()), BackupPollerBlockDelay: int64(cfg.EVM().BackupLogPollerBlockDelay()), } - logPoller = logpoller.NewLogPoller(logpoller.NewObservedORM(chainID, opts.DS, l), client, l, lpOpts) + logPoller = logpoller.NewLogPoller(logpoller.NewObservedORM(chainID, opts.DS, l), client, l, headTracker, lpOpts) } } diff --git a/core/chains/legacyevm/evm_txm.go b/core/chains/legacyevm/evm_txm.go index df1f4248ce2..cecfd4ffafe 100644 --- a/core/chains/legacyevm/evm_txm.go +++ b/core/chains/legacyevm/evm_txm.go @@ -43,7 +43,9 @@ func newEvmTxm( // build estimator from factory if opts.GenGasEstimator == nil { - estimator = gas.NewEstimator(lggr, client, cfg, cfg.GasEstimator()) + if estimator, err = gas.NewEstimator(lggr, client, cfg, cfg.GasEstimator()); err != nil { + return nil, nil, fmt.Errorf("failed to initialize estimator: %w", err) + } } else { estimator = opts.GenGasEstimator(chainID) } diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index 8f313ee45ef..93f7c40fe0c 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/chains/legacyevm/mocks/legacy_chain_container.go b/core/chains/legacyevm/mocks/legacy_chain_container.go index 527544de60d..ff73a4e1393 100644 --- a/core/chains/legacyevm/mocks/legacy_chain_container.go +++ b/core/chains/legacyevm/mocks/legacy_chain_container.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/cmd/app.go b/core/cmd/app.go index 378f7e8bd64..1ccb3da9a01 100644 --- a/core/cmd/app.go +++ b/core/cmd/app.go @@ -194,8 +194,7 @@ func NewApp(s *Shell) *cli.App { keysCommand("Cosmos", NewCosmosKeysClient(s)), keysCommand("Solana", NewSolanaKeysClient(s)), keysCommand("StarkNet", NewStarkNetKeysClient(s)), - keysCommand("DKGSign", NewDKGSignKeysClient(s)), - keysCommand("DKGEncrypt", NewDKGEncryptKeysClient(s)), + keysCommand("Aptos", NewAptosKeysClient(s)), initVRFKeysSubCmd(s), }, diff --git a/core/cmd/aptos_keys_commands.go b/core/cmd/aptos_keys_commands.go new file mode 100644 index 00000000000..cabad347510 --- /dev/null +++ b/core/cmd/aptos_keys_commands.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" +) + +type AptosKeyPresenter struct { + JAID + presenters.AptosKeyResource +} + +// RenderTable implements TableRenderer +func (p AptosKeyPresenter) RenderTable(rt RendererTable) error { + headers := []string{"ID", "Aptos Public Key"} + rows := [][]string{p.ToRow()} + + if _, err := rt.Write([]byte("🔑 Aptos Keys\n")); err != nil { + return err + } + renderList(headers, rows, rt.Writer) + + return utils.JustError(rt.Write([]byte("\n"))) +} + +func (p *AptosKeyPresenter) ToRow() []string { + row := []string{ + p.ID, + p.PubKey, + } + + return row +} + +type AptosKeyPresenters []AptosKeyPresenter + +// RenderTable implements TableRenderer +func (ps AptosKeyPresenters) RenderTable(rt RendererTable) error { + headers := []string{"ID", "Aptos Public Key"} + rows := [][]string{} + + for _, p := range ps { + rows = append(rows, p.ToRow()) + } + + if _, err := rt.Write([]byte("🔑 Aptos Keys\n")); err != nil { + return err + } + renderList(headers, rows, rt.Writer) + + return utils.JustError(rt.Write([]byte("\n"))) +} + +func NewAptosKeysClient(s *Shell) KeysClient { + return newKeysClient[aptoskey.Key, AptosKeyPresenter, AptosKeyPresenters]("Aptos", s) +} diff --git a/core/cmd/aptos_keys_commands_test.go b/core/cmd/aptos_keys_commands_test.go new file mode 100644 index 00000000000..c88a8e539a8 --- /dev/null +++ b/core/cmd/aptos_keys_commands_test.go @@ -0,0 +1,175 @@ +package cmd_test + +import ( + "bytes" + "context" + "flag" + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/urfave/cli" + + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/cmd" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" +) + +func TestAptosKeyPresenter_RenderTable(t *testing.T) { + t.Parallel() + + var ( + id = "1" + pubKey = "somepubkey" + buffer = bytes.NewBufferString("") + r = cmd.RendererTable{Writer: buffer} + ) + + p := cmd.AptosKeyPresenter{ + JAID: cmd.JAID{ID: id}, + AptosKeyResource: presenters.AptosKeyResource{ + JAID: presenters.NewJAID(id), + PubKey: pubKey, + }, + } + + // Render a single resource + require.NoError(t, p.RenderTable(r)) + + output := buffer.String() + assert.Contains(t, output, id) + assert.Contains(t, output, pubKey) + + // Render many resources + buffer.Reset() + ps := cmd.AptosKeyPresenters{p} + require.NoError(t, ps.RenderTable(r)) + + output = buffer.String() + assert.Contains(t, output, id) + assert.Contains(t, output, pubKey) +} + +func TestShell_AptosKeys(t *testing.T) { + app := startNewApplicationV2(t, nil) + ks := app.GetKeyStore().Aptos() + cleanup := func() { + ctx := context.Background() + keys, err := ks.GetAll() + require.NoError(t, err) + for _, key := range keys { + require.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) + } + requireAptosKeyCount(t, app, 0) + } + + t.Run("ListAptosKeys", func(tt *testing.T) { + defer cleanup() + ctx := testutils.Context(t) + client, r := app.NewShellAndRenderer() + key, err := app.GetKeyStore().Aptos().Create(ctx) + require.NoError(t, err) + requireAptosKeyCount(t, app, 1) + assert.Nil(t, cmd.NewAptosKeysClient(client).ListKeys(cltest.EmptyCLIContext())) + require.Equal(t, 1, len(r.Renders)) + keys := *r.Renders[0].(*cmd.AptosKeyPresenters) + assert.True(t, key.PublicKeyStr() == keys[0].PubKey) + }) + + t.Run("CreateAptosKey", func(tt *testing.T) { + defer cleanup() + client, _ := app.NewShellAndRenderer() + require.NoError(t, cmd.NewAptosKeysClient(client).CreateKey(nilContext)) + keys, err := app.GetKeyStore().Aptos().GetAll() + require.NoError(t, err) + require.Len(t, keys, 1) + }) + + t.Run("DeleteAptosKey", func(tt *testing.T) { + defer cleanup() + ctx := testutils.Context(t) + client, _ := app.NewShellAndRenderer() + key, err := app.GetKeyStore().Aptos().Create(ctx) + require.NoError(t, err) + requireAptosKeyCount(t, app, 1) + set := flag.NewFlagSet("test", 0) + flagSetApplyFromAction(cmd.NewAptosKeysClient(client).DeleteKey, set, "aptos") + + require.NoError(tt, set.Set("yes", "true")) + + strID := key.ID() + err = set.Parse([]string{strID}) + require.NoError(t, err) + c := cli.NewContext(nil, set, nil) + err = cmd.NewAptosKeysClient(client).DeleteKey(c) + require.NoError(t, err) + requireAptosKeyCount(t, app, 0) + }) + + t.Run("ImportExportAptosKey", func(tt *testing.T) { + defer cleanup() + defer deleteKeyExportFile(t) + ctx := testutils.Context(t) + client, _ := app.NewShellAndRenderer() + + _, err := app.GetKeyStore().Aptos().Create(ctx) + require.NoError(t, err) + + keys := requireAptosKeyCount(t, app, 1) + key := keys[0] + keyName := keyNameForTest(t) + + // Export test invalid id + set := flag.NewFlagSet("test Aptos export", 0) + flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ExportKey, set, "aptos") + + require.NoError(tt, set.Parse([]string{"0"})) + require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) + require.NoError(tt, set.Set("output", keyName)) + + c := cli.NewContext(nil, set, nil) + err = cmd.NewAptosKeysClient(client).ExportKey(c) + require.Error(t, err, "Error exporting") + require.Error(t, utils.JustError(os.Stat(keyName))) + + // Export test + set = flag.NewFlagSet("test Aptos export", 0) + flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ExportKey, set, "aptos") + + require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) + require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) + require.NoError(tt, set.Set("output", keyName)) + + c = cli.NewContext(nil, set, nil) + + require.NoError(t, cmd.NewAptosKeysClient(client).ExportKey(c)) + require.NoError(t, utils.JustError(os.Stat(keyName))) + + require.NoError(t, utils.JustError(app.GetKeyStore().Aptos().Delete(ctx, key.ID()))) + requireAptosKeyCount(t, app, 0) + + set = flag.NewFlagSet("test Aptos import", 0) + flagSetApplyFromAction(cmd.NewAptosKeysClient(client).ImportKey, set, "aptos") + + require.NoError(tt, set.Parse([]string{keyName})) + require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) + c = cli.NewContext(nil, set, nil) + require.NoError(t, cmd.NewAptosKeysClient(client).ImportKey(c)) + + requireAptosKeyCount(t, app, 1) + }) +} + +func requireAptosKeyCount(t *testing.T, app chainlink.Application, length int) []aptoskey.Key { + t.Helper() + keys, err := app.GetKeyStore().Aptos().GetAll() + require.NoError(t, err) + require.Len(t, keys, length) + return keys +} diff --git a/core/cmd/dkgencrypt_keys_commands.go b/core/cmd/dkgencrypt_keys_commands.go deleted file mode 100644 index ddcc80a33be..00000000000 --- a/core/cmd/dkgencrypt_keys_commands.go +++ /dev/null @@ -1,60 +0,0 @@ -package cmd - -import ( - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -type DKGEncryptKeyPresenter struct { - JAID - presenters.DKGEncryptKeyResource -} - -var _ TableRenderer = DKGEncryptKeyPresenter{} -var _ TableRenderer = DKGEncryptKeyPresenters{} - -// RenderTable implements TableRenderer -func (p DKGEncryptKeyPresenter) RenderTable(rt RendererTable) error { - headers := []string{"ID", "Public key"} - rows := [][]string{p.ToRow()} - - if _, err := rt.Write([]byte("🔑 DKGEncrypt Keys\n")); err != nil { - return err - } - renderList(headers, rows, rt.Writer) - - return utils.JustError(rt.Write([]byte("\n"))) -} - -func (p *DKGEncryptKeyPresenter) ToRow() []string { - row := []string{ - p.ID, - p.PublicKey, - } - - return row -} - -type DKGEncryptKeyPresenters []DKGEncryptKeyPresenter - -// RenderTable implements TableRenderer -func (ps DKGEncryptKeyPresenters) RenderTable(rt RendererTable) error { - headers := []string{"ID", "Public key"} - rows := [][]string{} - - for _, p := range ps { - rows = append(rows, p.ToRow()) - } - - if _, err := rt.Write([]byte("🔑 DKGEncrypt Keys\n")); err != nil { - return err - } - renderList(headers, rows, rt.Writer) - - return utils.JustError(rt.Write([]byte("\n"))) -} - -func NewDKGEncryptKeysClient(s *Shell) KeysClient { - return newKeysClient[dkgsignkey.Key, DKGEncryptKeyPresenter, DKGEncryptKeyPresenters]("DKGEncrypt", s) -} diff --git a/core/cmd/dkgencrypt_keys_commands_test.go b/core/cmd/dkgencrypt_keys_commands_test.go deleted file mode 100644 index 7b0de4f7774..00000000000 --- a/core/cmd/dkgencrypt_keys_commands_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package cmd_test - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli" - - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func TestDKGEncryptKeyPresenter_RenderTable(t *testing.T) { - t.Parallel() - - var ( - id = "1" - pubKey = "somepubkey" - buffer = bytes.NewBufferString("") - r = cmd.RendererTable{Writer: buffer} - ) - - p := cmd.DKGEncryptKeyPresenter{ - JAID: cmd.JAID{ID: id}, - DKGEncryptKeyResource: presenters.DKGEncryptKeyResource{ - JAID: presenters.NewJAID(id), - PublicKey: pubKey, - }, - } - - // Render a single resource - require.NoError(t, p.RenderTable(r)) - - output := buffer.String() - assert.Contains(t, output, id) - assert.Contains(t, output, pubKey) - - // Render many resources - buffer.Reset() - ps := cmd.DKGEncryptKeyPresenters{p} - require.NoError(t, ps.RenderTable(r)) - - output = buffer.String() - assert.Contains(t, output, id) - assert.Contains(t, output, pubKey) -} - -func TestShell_DKGEncryptKeys(t *testing.T) { - app := startNewApplicationV2(t, nil) - ks := app.GetKeyStore().DKGEncrypt() - cleanup := func() { - ctx := context.Background() - keys, err := ks.GetAll() - assert.NoError(t, err) - for _, key := range keys { - assert.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) - } - requireDKGEncryptKeyCount(t, app, 0) - } - - t.Run("ListDKGEncryptKeys", func(tt *testing.T) { - defer cleanup() - ctx := testutils.Context(t) - client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGEncrypt().Create(ctx) - assert.NoError(tt, err) - requireDKGEncryptKeyCount(t, app, 1) - assert.Nil(t, cmd.NewDKGEncryptKeysClient(client).ListKeys(cltest.EmptyCLIContext())) - assert.Equal(t, 1, len(r.Renders)) - keys := *r.Renders[0].(*cmd.DKGEncryptKeyPresenters) - assert.True(t, key.PublicKeyString() == keys[0].PublicKey) - }) - - t.Run("CreateDKGEncryptKey", func(tt *testing.T) { - defer cleanup() - client, _ := app.NewShellAndRenderer() - assert.NoError(tt, cmd.NewDKGEncryptKeysClient(client).CreateKey(nilContext)) - keys, err := app.GetKeyStore().DKGEncrypt().GetAll() - assert.NoError(tt, err) - assert.Len(t, keys, 1) - }) - - t.Run("DeleteDKGEncryptKey", func(tt *testing.T) { - defer cleanup() - ctx := testutils.Context(t) - client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGEncrypt().Create(ctx) - assert.NoError(tt, err) - requireDKGEncryptKeyCount(tt, app, 1) - set := flag.NewFlagSet("test", 0) - flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).DeleteKey, set, "") - - require.NoError(tt, set.Set("yes", "true")) - - strID := key.ID() - err = set.Parse([]string{strID}) - require.NoError(t, err) - c := cli.NewContext(nil, set, nil) - err = cmd.NewDKGEncryptKeysClient(client).DeleteKey(c) - assert.NoError(tt, err) - requireDKGEncryptKeyCount(tt, app, 0) - }) - - t.Run("ImportExportDKGEncryptKey", func(tt *testing.T) { - defer cleanup() - defer deleteKeyExportFile(tt) - ctx := testutils.Context(t) - client, _ := app.NewShellAndRenderer() - - _, err := app.GetKeyStore().DKGEncrypt().Create(ctx) - require.NoError(tt, err) - - keys := requireDKGEncryptKeyCount(tt, app, 1) - key := keys[0] - t.Log("key id:", key.ID()) - keyName := keyNameForTest(t) - - // Export test invalid id - set := flag.NewFlagSet("test DKGEncrypt export", 0) - flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") - - require.NoError(tt, set.Parse([]string{"0"})) - require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) - require.NoError(tt, set.Set("output", keyName)) - - c := cli.NewContext(nil, set, nil) - err = cmd.NewDKGEncryptKeysClient(client).ExportKey(c) - require.Error(tt, err, "Error exporting") - require.Error(tt, utils.JustError(os.Stat(keyName))) - - // Export test - set = flag.NewFlagSet("test DKGEncrypt export", 0) - flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ExportKey, set, "") - - require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) - require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) - require.NoError(tt, set.Set("output", keyName)) - - c = cli.NewContext(nil, set, nil) - - require.NoError(tt, cmd.NewDKGEncryptKeysClient(client).ExportKey(c)) - require.NoError(tt, utils.JustError(os.Stat(keyName))) - - require.NoError(tt, utils.JustError(app.GetKeyStore().DKGEncrypt().Delete(ctx, key.ID()))) - requireDKGEncryptKeyCount(tt, app, 0) - - //Import test - set = flag.NewFlagSet("test DKGEncrypt import", 0) - flagSetApplyFromAction(cmd.NewDKGEncryptKeysClient(client).ImportKey, set, "") - - require.NoError(tt, set.Parse([]string{keyName})) - require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) - - c = cli.NewContext(nil, set, nil) - require.NoError(tt, cmd.NewDKGEncryptKeysClient(client).ImportKey(c)) - - requireDKGEncryptKeyCount(tt, app, 1) - }) -} - -func requireDKGEncryptKeyCount(t *testing.T, app chainlink.Application, length int) []dkgencryptkey.Key { - t.Helper() - keys, err := app.GetKeyStore().DKGEncrypt().GetAll() - require.NoError(t, err) - require.Len(t, keys, length) - return keys -} diff --git a/core/cmd/dkgsign_keys_commands.go b/core/cmd/dkgsign_keys_commands.go deleted file mode 100644 index b0435450e32..00000000000 --- a/core/cmd/dkgsign_keys_commands.go +++ /dev/null @@ -1,60 +0,0 @@ -package cmd - -import ( - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -type DKGSignKeyPresenter struct { - JAID - presenters.DKGSignKeyResource -} - -var _ TableRenderer = DKGSignKeyPresenter{} -var _ TableRenderer = DKGSignKeyPresenters{} - -// RenderTable implements TableRenderer -func (p DKGSignKeyPresenter) RenderTable(rt RendererTable) error { - headers := []string{"ID", "Public key"} - rows := [][]string{p.ToRow()} - - if _, err := rt.Write([]byte("🔑 DKGSign Keys\n")); err != nil { - return err - } - renderList(headers, rows, rt.Writer) - - return utils.JustError(rt.Write([]byte("\n"))) -} - -func (p *DKGSignKeyPresenter) ToRow() []string { - row := []string{ - p.ID, - p.PublicKey, - } - - return row -} - -type DKGSignKeyPresenters []DKGSignKeyPresenter - -// RenderTable implements TableRenderer -func (ps DKGSignKeyPresenters) RenderTable(rt RendererTable) error { - headers := []string{"ID", "Public key"} - rows := [][]string{} - - for _, p := range ps { - rows = append(rows, p.ToRow()) - } - - if _, err := rt.Write([]byte("🔑 DKGSign Keys\n")); err != nil { - return err - } - renderList(headers, rows, rt.Writer) - - return utils.JustError(rt.Write([]byte("\n"))) -} - -func NewDKGSignKeysClient(s *Shell) KeysClient { - return newKeysClient[dkgsignkey.Key, DKGSignKeyPresenter, DKGSignKeyPresenters]("DKGSign", s) -} diff --git a/core/cmd/dkgsign_keys_commands_test.go b/core/cmd/dkgsign_keys_commands_test.go deleted file mode 100644 index 777e8a0a3c3..00000000000 --- a/core/cmd/dkgsign_keys_commands_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package cmd_test - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/cli" - - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func TestDKGSignKeyPresenter_RenderTable(t *testing.T) { - t.Parallel() - - var ( - id = "1" - pubKey = "somepubkey" - buffer = bytes.NewBufferString("") - r = cmd.RendererTable{Writer: buffer} - ) - - p := cmd.DKGSignKeyPresenter{ - JAID: cmd.JAID{ID: id}, - DKGSignKeyResource: presenters.DKGSignKeyResource{ - JAID: presenters.NewJAID(id), - PublicKey: pubKey, - }, - } - - // Render a single resource - require.NoError(t, p.RenderTable(r)) - - output := buffer.String() - assert.Contains(t, output, id) - assert.Contains(t, output, pubKey) - - // Render many resources - buffer.Reset() - ps := cmd.DKGSignKeyPresenters{p} - require.NoError(t, ps.RenderTable(r)) - - output = buffer.String() - assert.Contains(t, output, id) - assert.Contains(t, output, pubKey) -} - -func TestShell_DKGSignKeys(t *testing.T) { - app := startNewApplicationV2(t, nil) - ks := app.GetKeyStore().DKGSign() - cleanup := func() { - ctx := context.Background() - keys, err := ks.GetAll() - assert.NoError(t, err) - for _, key := range keys { - assert.NoError(t, utils.JustError(ks.Delete(ctx, key.ID()))) - } - requireDKGSignKeyCount(t, app, 0) - } - - t.Run("ListDKGSignKeys", func(tt *testing.T) { - defer cleanup() - ctx := testutils.Context(t) - client, r := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGSign().Create(ctx) - assert.NoError(tt, err) - requireDKGSignKeyCount(t, app, 1) - assert.Nil(t, cmd.NewDKGSignKeysClient(client).ListKeys(cltest.EmptyCLIContext())) - assert.Equal(t, 1, len(r.Renders)) - keys := *r.Renders[0].(*cmd.DKGSignKeyPresenters) - assert.True(t, key.PublicKeyString() == keys[0].PublicKey) - }) - - t.Run("CreateDKGSignKey", func(tt *testing.T) { - defer cleanup() - client, _ := app.NewShellAndRenderer() - assert.NoError(tt, cmd.NewDKGSignKeysClient(client).CreateKey(nilContext)) - keys, err := app.GetKeyStore().DKGSign().GetAll() - assert.NoError(tt, err) - assert.Len(t, keys, 1) - }) - - t.Run("DeleteDKGSignKey", func(tt *testing.T) { - defer cleanup() - ctx := testutils.Context(t) - client, _ := app.NewShellAndRenderer() - key, err := app.GetKeyStore().DKGSign().Create(ctx) - assert.NoError(tt, err) - requireDKGSignKeyCount(tt, app, 1) - set := flag.NewFlagSet("test", 0) - flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).DeleteKey, set, "") - - require.NoError(tt, set.Set("yes", "true")) - strID := key.ID() - err = set.Parse([]string{strID}) - require.NoError(t, err) - c := cli.NewContext(nil, set, nil) - err = cmd.NewDKGSignKeysClient(client).DeleteKey(c) - assert.NoError(tt, err) - requireDKGSignKeyCount(tt, app, 0) - }) - - t.Run("ImportExportDKGSignKey", func(tt *testing.T) { - defer cleanup() - defer deleteKeyExportFile(tt) - ctx := testutils.Context(t) - client, _ := app.NewShellAndRenderer() - - _, err := app.GetKeyStore().DKGSign().Create(ctx) - require.NoError(tt, err) - - keys := requireDKGSignKeyCount(tt, app, 1) - key := keys[0] - t.Log("key id:", key.ID()) - keyName := keyNameForTest(t) - - // Export test invalid id - set := flag.NewFlagSet("test DKGSign export", 0) - flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") - - require.NoError(tt, set.Parse([]string{"0"})) - require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) - require.NoError(tt, set.Set("output", keyName)) - - c := cli.NewContext(nil, set, nil) - err = cmd.NewDKGSignKeysClient(client).ExportKey(c) - require.Error(tt, err) - require.Error(tt, utils.JustError(os.Stat(keyName))) - - // Export test - set = flag.NewFlagSet("test DKGSign export", 0) - flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ExportKey, set, "") - - require.NoError(tt, set.Parse([]string{fmt.Sprint(key.ID())})) - require.NoError(tt, set.Set("new-password", "../internal/fixtures/incorrect_password.txt")) - require.NoError(tt, set.Set("output", keyName)) - - c = cli.NewContext(nil, set, nil) - - require.NoError(tt, cmd.NewDKGSignKeysClient(client).ExportKey(c)) - require.NoError(tt, utils.JustError(os.Stat(keyName))) - - require.NoError(tt, utils.JustError(app.GetKeyStore().DKGSign().Delete(ctx, key.ID()))) - requireDKGSignKeyCount(tt, app, 0) - - set = flag.NewFlagSet("test DKGSign import", 0) - flagSetApplyFromAction(cmd.NewDKGSignKeysClient(client).ImportKey, set, "") - - require.NoError(tt, set.Parse([]string{keyName})) - require.NoError(tt, set.Set("old-password", "../internal/fixtures/incorrect_password.txt")) - - c = cli.NewContext(nil, set, nil) - require.NoError(tt, cmd.NewDKGSignKeysClient(client).ImportKey(c)) - - requireDKGSignKeyCount(tt, app, 1) - }) -} - -func requireDKGSignKeyCount(t *testing.T, app chainlink.Application, length int) []dkgsignkey.Key { - t.Helper() - keys, err := app.GetKeyStore().DKGSign().GetAll() - require.NoError(t, err) - require.Len(t, keys, length) - return keys -} diff --git a/core/cmd/mocks/prompter.go b/core/cmd/mocks/prompter.go index 38c1d327fb3..c2dff9fa61f 100644 --- a/core/cmd/mocks/prompter.go +++ b/core/cmd/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go deleted file mode 100644 index 7f5b0321480..00000000000 --- a/core/cmd/ocr2vrf_configure_commands.go +++ /dev/null @@ -1,509 +0,0 @@ -package cmd - -import ( - "context" - "encoding/hex" - "fmt" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/pelletier/go-toml" - "github.com/pkg/errors" - "github.com/urfave/cli" - - "github.com/jmoiron/sqlx" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type SetupOCR2VRFNodePayload struct { - OnChainPublicKey string - OffChainPublicKey string - ConfigPublicKey string - PeerID string - Transmitter string - DkgEncrypt string - DkgSign string - SendingKeys []string -} - -type dkgTemplateArgs struct { - contractID string - ocrKeyBundleID string - p2pv2BootstrapperPeerID string - p2pv2BootstrapperPort string - transmitterID string - useForwarder bool - chainID int64 - encryptionPublicKey string - keyID string - signingPublicKey string -} - -type ocr2vrfTemplateArgs struct { - dkgTemplateArgs - vrfBeaconAddress string - vrfCoordinatorAddress string - linkEthFeedAddress string - sendingKeys []string -} - -const DKGTemplate = ` -# DKGSpec -type = "offchainreporting2" -schemaVersion = 1 -name = "ocr2" -maxTaskDuration = "30s" -contractID = "%s" -ocrKeyBundleID = "%s" -relay = "evm" -pluginType = "dkg" -transmitterID = "%s" -forwardingAllowed = %t -%s - -[relayConfig] -chainID = %d - -[pluginConfig] -EncryptionPublicKey = "%s" -KeyID = "%s" -SigningPublicKey = "%s" -` - -const OCR2VRFTemplate = ` -type = "offchainreporting2" -schemaVersion = 1 -name = "ocr2vrf-chainID-%d" -maxTaskDuration = "30s" -contractID = "%s" -ocrKeyBundleID = "%s" -relay = "evm" -pluginType = "ocr2vrf" -transmitterID = "%s" -forwardingAllowed = %t -%s - -[relayConfig] -chainID = %d -sendingKeys = [%s] - -[pluginConfig] -dkgEncryptionPublicKey = "%s" -dkgSigningPublicKey = "%s" -dkgKeyID = "%s" -dkgContractAddress = "%s" - -vrfCoordinatorAddress = "%s" -linkEthFeedAddress = "%s" -` - -const BootstrapTemplate = ` -type = "bootstrap" -schemaVersion = 1 -name = "bootstrap-chainID-%d" -id = "1" -contractID = "%s" -relay = "evm" - -[relayConfig] -chainID = %d -` - -const forwarderAdditionalEOACount = 4 - -func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, ec *ethclient.Client) (*SetupOCR2VRFNodePayload, error) { - ctx := s.ctx() - lggr := logger.Sugared(s.Logger.Named("ConfigureOCR2VRFNode")) - lggr.Infow( - fmt.Sprintf("Configuring Chainlink Node for job type %s %s at commit %s", c.String("job-type"), static.Version, static.Sha), - "Version", static.Version, "SHA", static.Sha) - - var pwd, vrfpwd *string - if passwordFile := c.String("password"); passwordFile != "" { - p, err := utils.PasswordFromFile(passwordFile) - if err != nil { - return nil, errors.Wrap(err, "error reading password from file") - } - pwd = &p - } - if vrfPasswordFile := c.String("vrfpassword"); len(vrfPasswordFile) != 0 { - p, err := utils.PasswordFromFile(vrfPasswordFile) - if err != nil { - return nil, errors.Wrapf(err, "error reading VRF password from vrfpassword file \"%s\"", vrfPasswordFile) - } - vrfpwd = &p - } - - s.Config.SetPasswords(pwd, vrfpwd) - - err := s.Config.Validate() - if err != nil { - return nil, s.errorOut(errors.Wrap(err, "config validation failed")) - } - - cfg := s.Config - ldb := pg.NewLockedDB(cfg.AppID(), cfg.Database(), cfg.Database().Lock(), lggr) - - if err = ldb.Open(ctx); err != nil { - return nil, s.errorOut(errors.Wrap(err, "opening db")) - } - defer lggr.ErrorIfFn(ldb.Close, "Error closing db") - - app, err := s.AppFactory.NewApplication(ctx, s.Config, lggr, ldb.DB()) - if err != nil { - return nil, s.errorOut(errors.Wrap(err, "fatal error instantiating application")) - } - - chainID := c.Int64("chainID") - - // Initialize keystore and generate keys. - keyStore := app.GetKeyStore() - err = setupKeystore(ctx, s, app, keyStore) - if err != nil { - return nil, s.errorOut(err) - } - - // Start application. - err = app.Start(ctx) - if err != nil { - return nil, s.errorOut(err) - } - - // Close application. - defer lggr.ErrorIfFn(app.Stop, "Failed to Stop application") - - // Initialize transmitter settings. - var sendingKeys []string - var sendingKeysAddresses []common.Address - useForwarder := c.Bool("use-forwarder") - ethKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(ctx, big.NewInt(chainID)) - if err != nil { - return nil, s.errorOut(err) - } - transmitterID := ethKeys[0].Address.String() - - // Populate sendingKeys with current ETH keys. - for _, k := range ethKeys { - sendingKeys = append(sendingKeys, k.Address.String()) - sendingKeysAddresses = append(sendingKeysAddresses, k.Address) - } - - if useForwarder { - // Add extra sending keys if using a forwarder. - sendingKeys, sendingKeysAddresses, err = s.appendForwarders(ctx, chainID, app.GetKeyStore().Eth(), sendingKeys, sendingKeysAddresses) - if err != nil { - return nil, err - } - err = s.authorizeForwarder(c, ldb.DB(), chainID, ec, owner, sendingKeysAddresses) - if err != nil { - return nil, err - } - } - - // Get all configuration parameters. - keyID := c.String("keyID") - dkgEncrypt, _ := app.GetKeyStore().DKGEncrypt().GetAll() - dkgSign, _ := app.GetKeyStore().DKGSign().GetAll() - dkgEncryptKey := dkgEncrypt[0].PublicKeyString() - dkgSignKey := dkgSign[0].PublicKeyString() - p2p, _ := app.GetKeyStore().P2P().GetAll() - ocr2List, _ := app.GetKeyStore().OCR2().GetAll() - peerID := p2p[0].PeerID().Raw() - if !c.Bool("isBootstrapper") { - peerID = c.String("bootstrapperPeerID") - } - - // Find the EVM OCR2 bundle. - var ocr2 ocr2key.KeyBundle - for _, ocr2Item := range ocr2List { - if ocr2Item.ChainType() == chaintype.EVM { - ocr2 = ocr2Item - } - } - if ocr2 == nil { - return nil, s.errorOut(errors.Wrap(job.ErrNoSuchKeyBundle, "evm OCR2 key bundle not found")) - } - offChainPublicKey := ocr2.OffchainPublicKey() - configPublicKey := ocr2.ConfigEncryptionPublicKey() - - if c.Bool("isBootstrapper") { - // Set up bootstrapper job if bootstrapper. - err = createBootstrapperJob(ctx, lggr, c, app) - } else if c.String("job-type") == "DKG" { - // Set up DKG job. - err = createDKGJob(ctx, lggr, app, dkgTemplateArgs{ - contractID: c.String("contractID"), - ocrKeyBundleID: ocr2.ID(), - p2pv2BootstrapperPeerID: peerID, - p2pv2BootstrapperPort: c.String("bootstrapPort"), - transmitterID: transmitterID, - useForwarder: useForwarder, - chainID: chainID, - encryptionPublicKey: dkgEncryptKey, - keyID: keyID, - signingPublicKey: dkgSignKey, - }) - } else if c.String("job-type") == "OCR2VRF" { - // Set up OCR2VRF job. - err = createOCR2VRFJob(ctx, lggr, app, ocr2vrfTemplateArgs{ - dkgTemplateArgs: dkgTemplateArgs{ - contractID: c.String("dkg-address"), - ocrKeyBundleID: ocr2.ID(), - p2pv2BootstrapperPeerID: peerID, - p2pv2BootstrapperPort: c.String("bootstrapPort"), - transmitterID: transmitterID, - useForwarder: useForwarder, - chainID: chainID, - encryptionPublicKey: dkgEncryptKey, - keyID: keyID, - signingPublicKey: dkgSignKey, - }, - vrfBeaconAddress: c.String("vrf-beacon-address"), - vrfCoordinatorAddress: c.String("vrf-coordinator-address"), - linkEthFeedAddress: c.String("link-eth-feed-address"), - sendingKeys: sendingKeys, - }) - } else { - err = fmt.Errorf("unknown job type: %s", c.String("job-type")) - } - - if err != nil { - return nil, err - } - - return &SetupOCR2VRFNodePayload{ - OnChainPublicKey: ocr2.OnChainPublicKey(), - OffChainPublicKey: hex.EncodeToString(offChainPublicKey[:]), - ConfigPublicKey: hex.EncodeToString(configPublicKey[:]), - PeerID: p2p[0].PeerID().Raw(), - Transmitter: transmitterID, - DkgEncrypt: dkgEncryptKey, - DkgSign: dkgSignKey, - SendingKeys: sendingKeys, - }, nil -} - -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(ctx) - if err != nil { - return nil, nil, err - } - - // Enable the sending key for the current chain. - err = ks.Enable(ctx, k.Address, big.NewInt(chainID)) - if err != nil { - return nil, nil, err - } - - sendingKeys = append(sendingKeys, k.Address.String()) - sendingKeysAddresses = append(sendingKeysAddresses, k.Address) - } - - return sendingKeys, sendingKeysAddresses, nil -} - -func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, chainID int64, ec *ethclient.Client, owner *bind.TransactOpts, sendingKeysAddresses []common.Address) error { - ctx := s.ctx() - // Replace the transmitter ID with the forwarder address. - forwarderAddress := c.String("forwarder-address") - - // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the - // forwarder will not be recognized. - ctx, cancel := context.WithTimeout(ctx, 300*time.Second) - defer cancel() - f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) - if err != nil { - return err - } - tx, err := f.SetAuthorizedSenders(owner, sendingKeysAddresses) - if err != nil { - return err - } - _, err = bind.WaitMined(ctx, ec, tx) - if err != nil { - return err - } - - // Create forwarder for management in forwarder_manager.go. - orm := forwarders.NewORM(db) - _, err = orm.CreateForwarder(ctx, common.HexToAddress(forwarderAddress), *ubig.NewI(chainID)) - if err != nil { - return err - } - - return nil -} - -func setupKeystore(ctx context.Context, cli *Shell, app chainlink.Application, keyStore keystore.Master) error { - if err := cli.KeyStoreAuthenticator.authenticate(ctx, keyStore, cli.Config.Password()); err != nil { - return errors.Wrap(err, "error authenticating keystore") - } - - if cli.Config.EVMEnabled() { - chains, err := app.GetRelayers().LegacyEVMChains().List() - if err != nil { - return fmt.Errorf("failed to get legacy evm chains") - } - for _, ch := range chains { - if err = keyStore.Eth().EnsureKeys(ctx, ch.ID()); err != nil { - return errors.Wrap(err, "failed to ensure keystore keys") - } - } - } - - var enabledChains []chaintype.ChainType - if cli.Config.EVMEnabled() { - enabledChains = append(enabledChains, chaintype.EVM) - } - if cli.Config.CosmosEnabled() { - enabledChains = append(enabledChains, chaintype.Cosmos) - } - if cli.Config.SolanaEnabled() { - enabledChains = append(enabledChains, chaintype.Solana) - } - if cli.Config.StarkNetEnabled() { - enabledChains = append(enabledChains, chaintype.StarkNet) - } - - if err := keyStore.OCR2().EnsureKeys(ctx, enabledChains...); err != nil { - return errors.Wrap(err, "failed to ensure ocr key") - } - - if err := keyStore.DKGSign().EnsureKey(ctx); err != nil { - return errors.Wrap(err, "failed to ensure dkgsign key") - } - - if err := keyStore.DKGEncrypt().EnsureKey(ctx); err != nil { - return errors.Wrap(err, "failed to ensure dkgencrypt key") - } - - if err := keyStore.P2P().EnsureKey(ctx); err != nil { - return errors.Wrap(err, "failed to ensure p2p key") - } - - return nil -} - -func createBootstrapperJob(ctx context.Context, lggr logger.Logger, c *cli.Context, app chainlink.Application) error { - sp := fmt.Sprintf(BootstrapTemplate, - c.Int64("chainID"), - c.String("contractID"), - c.Int64("chainID"), - ) - var jb job.Job - err := toml.Unmarshal([]byte(sp), &jb) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - var os job.BootstrapSpec - err = toml.Unmarshal([]byte(sp), &os) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - jb.BootstrapSpec = &os - - err = app.AddJobV2(ctx, &jb) - if err != nil { - return errors.Wrap(err, "failed to add job") - } - lggr.Info("bootstrap spec:", sp) - - // Give a cooldown - time.Sleep(time.Second) - - return nil -} - -func createDKGJob(ctx context.Context, lggr logger.Logger, app chainlink.Application, args dkgTemplateArgs) error { - sp := fmt.Sprintf(DKGTemplate, - args.contractID, - args.ocrKeyBundleID, - args.transmitterID, - args.useForwarder, - fmt.Sprintf(`p2pv2Bootstrappers = ["%s@127.0.0.1:%s"]`, args.p2pv2BootstrapperPeerID, args.p2pv2BootstrapperPort), - args.chainID, - args.encryptionPublicKey, - args.keyID, - args.signingPublicKey, - ) - - var jb job.Job - err := toml.Unmarshal([]byte(sp), &jb) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - var os job.OCR2OracleSpec - err = toml.Unmarshal([]byte(sp), &os) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - jb.OCR2OracleSpec = &os - - err = app.AddJobV2(ctx, &jb) - if err != nil { - return errors.Wrap(err, "failed to add job") - } - lggr.Info("dkg spec:", sp) - - return nil -} - -func createOCR2VRFJob(ctx context.Context, lggr logger.Logger, app chainlink.Application, args ocr2vrfTemplateArgs) error { - var sendingKeysString = fmt.Sprintf(`"%s"`, args.sendingKeys[0]) - for x := 1; x < len(args.sendingKeys); x++ { - sendingKeysString = fmt.Sprintf(`%s,"%s"`, sendingKeysString, args.sendingKeys[x]) - } - sp := fmt.Sprintf(OCR2VRFTemplate, - args.chainID, - args.vrfBeaconAddress, - args.ocrKeyBundleID, - args.transmitterID, - args.useForwarder, - fmt.Sprintf(`p2pv2Bootstrappers = ["%s@127.0.0.1:%s"]`, args.p2pv2BootstrapperPeerID, args.p2pv2BootstrapperPort), - args.chainID, - sendingKeysString, - args.encryptionPublicKey, - args.signingPublicKey, - args.keyID, - args.contractID, - args.vrfCoordinatorAddress, - args.linkEthFeedAddress, - ) - - var jb job.Job - err := toml.Unmarshal([]byte(sp), &jb) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - var os job.OCR2OracleSpec - err = toml.Unmarshal([]byte(sp), &os) - if err != nil { - return errors.Wrap(err, "failed to unmarshal job spec") - } - jb.OCR2OracleSpec = &os - - err = app.AddJobV2(ctx, &jb) - if err != nil { - return errors.Wrap(err, "failed to add job") - } - lggr.Info("ocr2vrf spec:", sp) - - return nil -} diff --git a/core/config/app_config.go b/core/config/app_config.go index 869477218db..112e242636f 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -25,6 +25,7 @@ type AppConfig interface { CosmosEnabled() bool SolanaEnabled() bool StarkNetEnabled() bool + AptosEnabled() bool Validate() error ValidateDB() error diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index a222d5269d7..38c8cb8354f 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -85,6 +85,18 @@ RPCDefaultBatchSize = 250 # Default # available from the connected node via RPC, due to race conditions in the code of the remote ETH node. In this case you will get false # "zero" blocks that are missing transactions. RPCBlockQueryDelay = 1 # Default +# FinalizedBlockOffset defines the number of blocks by which the latest finalized block will be shifted/delayed. +# For example, suppose RPC returns block 100 as the latest finalized. In that case, the CL Node will treat block `100 - FinalizedBlockOffset` as the latest finalized block and `latest - FinalityDepth - FinalizedBlockOffset` in case of `FinalityTagEnabled = false.` +# With `EnforceRepeatableRead = true,` RPC is considered healthy only if its most recent finalized block is larger or equal to the highest finalized block observed by the CL Node minus `FinalizedBlockOffset.` +# Higher values of `FinalizedBlockOffset` with `EnforceRepeatableRead = true` reduce the number of false `FinalizedBlockOutOfSync` declarations on healthy RPCs that are slightly lagging behind due to network delays. +# This may increase the number of healthy RPCs and reduce the probability that the CL Node will not have any healthy alternatives to the active RPC. +# CAUTION: Setting this to values higher than 0 may delay transaction creation in products (e.g., CCIP, Automation) that base their decision on finalized on-chain events. +# PoS chains with `FinalityTagEnabled=true` and batched (epochs) blocks finalization (e.g., Ethereum Mainnet) must be treated with special care as a minor increase in the `FinalizedBlockOffset` may lead to significant delays. +# For example, let's say that `FinalizedBlockOffset = 1` and blocks are finalized in batches of 32. +# The latest finalized block on chain is 64, so block 63 is the latest finalized for CL Node. +# Block 64 will be treated as finalized by CL Node only when chain's latest finalized block is 65. As chain finalizes blocks in batches of 32, +# CL Node has to wait for a whole new batch to be finalized to treat block 64 as finalized. +FinalizedBlockOffset = 0 # Default [EVM.Transactions] # ForwardersEnabled enables or disables sending transactions through forwarder contracts. @@ -368,7 +380,17 @@ NodeIsSyncingEnabled = false # Default # # Set to 0 to disable. FinalizedBlockPollInterval = '5s' # Default - +# EnforceRepeatableRead defines if Core should only use RPCs whose most recently finalized block is greater or equal to +# `highest finalized block - FinalizedBlockOffset`. In other words, exclude RPCs lagging on latest finalized +# block. +# +# Set false to disable +EnforceRepeatableRead = false # Default +# DeathDeclarationDelay defines the minimum duration an RPC must be in unhealthy state before producing an error log message. +# Larger values might be helpful to reduce the noisiness of health checks like `EnforceRepeatableRead = true', which might be falsely +# trigger declaration of `FinalizedBlockOutOfSync` due to insignificant network delays in broadcasting of the finalized state among RPCs. +# RPC will not be picked to handle a request even if this option is set to a nonzero value. +DeathDeclarationDelay = '10s' # Default # **ADVANCED** # Errors enable the node to provide custom regex patterns to match against error messages from RPCs. [EVM.NodePool.Errors] diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go index fb01cc29cd0..43889566c70 100644 --- a/core/config/mocks/telemetry_ingress.go +++ b/core/config/mocks/telemetry_ingress.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/config/mocks/telemetry_ingress_endpoint.go b/core/config/mocks/telemetry_ingress_endpoint.go index e5f8c3106eb..11eebd373ef 100644 --- a/core/config/mocks/telemetry_ingress_endpoint.go +++ b/core/config/mocks/telemetry_ingress_endpoint.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/gethwrappers/ocr2vrf/generated/dkg/dkg.go b/core/gethwrappers/ocr2vrf/generated/dkg/dkg.go deleted file mode 100644 index 7a18b7f55bd..00000000000 --- a/core/gethwrappers/ocr2vrf/generated/dkg/dkg.go +++ /dev/null @@ -1,1274 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package dkg - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -type KeyDataStructKeyData struct { - PublicKey []byte - Hashes [][32]byte -} - -var DKGMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualLength\",\"type\":\"uint256\"}],\"name\":\"CalldataLengthMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedNumSignatures\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rsLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ssLength\",\"type\":\"uint256\"}],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"expectedLength\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"actualLength\",\"type\":\"uint256\"}],\"name\":\"InvalidOnchainConfigLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyIDCopyFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"numFaultyOracles\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"}],\"name\":\"NumberOfFaultyOraclesTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"repeatedSignerAddress\",\"type\":\"address\"}],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"repeatedTransmitterAddress\",\"type\":\"address\"}],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numTransmitters\",\"type\":\"uint256\"}],\"name\":\"SignersTransmittersMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"maxOracles\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"providedOracles\",\"type\":\"uint256\"}],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contractDKGClient\",\"name\":\"client\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"DKGClientError\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashes\",\"type\":\"bytes32[]\"}],\"indexed\":false,\"internalType\":\"structKeyDataStruct.KeyData\",\"name\":\"key\",\"type\":\"tuple\"}],\"name\":\"KeyGenerated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyID\",\"type\":\"bytes32\"},{\"internalType\":\"contractDKGClient\",\"name\":\"clientAddress\",\"type\":\"address\"}],\"name\":\"addClient\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_keyID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_configDigest\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashes\",\"type\":\"bytes32[]\"}],\"internalType\":\"structKeyDataStruct.KeyData\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyID\",\"type\":\"bytes32\"},{\"internalType\":\"contractDKGClient\",\"name\":\"clientAddress\",\"type\":\"address\"}],\"name\":\"removeClient\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b503380600081620000695760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200009c576200009c81620000a5565b50505062000150565b336001600160a01b03821603620000ff5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000060565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b612b8080620001606000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063c3105a6b1161005b578063c3105a6b146101db578063e3d0e712146101fb578063f2fde38b1461020e57600080fd5b80638da5cb5b14610176578063afcb95d71461019e578063b1dc65a4146101c857600080fd5b806379ba5097116100b257806379ba50971461012b5780637bf1ffc51461013357806381ff70481461014657600080fd5b8063181f5a77146100ce5780635429a79e14610116575b600080fd5b604080518082018252600981527f444b4720302e302e3100000000000000000000000000000000000000000000006020820152905161010d9190611fc8565b60405180910390f35b610129610124366004612004565b610221565b005b6101296104b0565b610129610141366004612004565b6105b2565b6007546005546040805163ffffffff8085168252640100000000909404909316602084015282015260600161010d565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b6005546004546040805160008152602081019390935263ffffffff9091169082015260600161010d565b6101296101d6366004612080565b61061e565b6101ee6101e9366004612165565b610761565b60405161010d9190612187565b6101296102093660046123dd565b61088a565b61012961021c3660046124aa565b6111ec565b610229611200565b60008281526002602090815260408083208054825181850281018501909352808352919290919083018282801561029657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161026b575b505050505090506000815167ffffffffffffffff8111156102b9576102b961220d565b6040519080825280602002602001820160405280156102e2578160200160208202803683370190505b5090506000805b83518110156103b9578473ffffffffffffffffffffffffffffffffffffffff1684828151811061031b5761031b6124c7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff161461039957848361034a8484612525565b8151811061035a5761035a6124c7565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506103a7565b816103a381612538565b9250505b806103b181612538565b9150506102e9565b5060008184516103c99190612525565b67ffffffffffffffff8111156103e1576103e161220d565b60405190808252806020026020018201604052801561040a578160200160208202803683370190505b50905060005b82855161041d9190612525565b81101561048757838181518110610436576104366124c7565b6020026020010151828281518110610450576104506124c7565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528061047f81612538565b915050610410565b50600086815260026020908152604090912082516104a792840190611e61565b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6105ba611200565b600091825260026020908152604083208054600181018255908452922090910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005a604080516020601f8b018190048102820181019092528981529192508a3591818c01359161066e9184918491908e908e908190840183828082843760009201919091525061128392505050565b6040805183815263ffffffff600884901c1660208201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260055480825260065460ff808216602085015261010090910416928201929092529083146107215780516040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101919091526024810184905260440161052d565b61072f8b8b8b8b8b8b611512565b6107408c8c8c8c8c8c8c8c89611599565b50505063ffffffff811061075657610756612570565b505050505050505050565b604080518082019091526060808252602082015260008381526003602090815260408083208584529091529081902081518083019092528054829082906107a79061259f565b80601f01602080910402602001604051908101604052809291908181526020018280546107d39061259f565b80156108205780601f106107f557610100808354040283529160200191610820565b820191906000526020600020905b81548152906001019060200180831161080357829003601f168201915b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561087857602002820191906000526020600020905b815481526020019060010190808311610864575b50505050508152505090505b92915050565b8551855185601f8311156108d4576040517f809fc428000000000000000000000000000000000000000000000000000000008152601f60048201526024810184905260440161052d565b818314610917576040517f988a0804000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260440161052d565b6109228160036125f2565b60ff168311610969576040517ffda9db7800000000000000000000000000000000000000000000000000000000815260ff821660048201526024810184905260440161052d565b8060ff166000036109a6576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109ae611200565b6040805160c0810182528a8152602081018a905260ff8916918101919091526060810187905267ffffffffffffffff8616608082015260a081018590525b60095415610ba157600954600090610a0690600190612525565b9050600060098281548110610a1d57610a1d6124c7565b6000918252602082200154600a805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110610a5757610a576124c7565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526008909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600980549192509080610ad757610ad7612615565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055600a805480610b4057610b40612615565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055506109ec915050565b60005b81515181101561101c5760006008600084600001518481518110610bca57610bca6124c7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115610c1457610c14612644565b14610c84578151805182908110610c2d57610c2d6124c7565b60200260200101516040517f7451f83e00000000000000000000000000000000000000000000000000000000815260040161052d919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040805180820190915260ff82168152600160208201528251805160089160009185908110610cb557610cb56124c7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610d5657610d56612644565b021790555060009150610d669050565b6008600084602001518481518110610d8057610d806124c7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115610dca57610dca612644565b14610e3c5781602001518181518110610de557610de56124c7565b60200260200101516040517fe8d2989900000000000000000000000000000000000000000000000000000000815260040161052d919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040805180820190915260ff821681526020810160028152506008600084602001518481518110610e6f57610e6f6124c7565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610f1057610f10612644565b021790555050825180516009925083908110610f2e57610f2e6124c7565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558201518051600a919083908110610faa57610faa6124c7565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061101481612538565b915050610ba4565b506040810151600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600754640100000000900463ffffffff1661106c611a2f565b6007805463ffffffff928316640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff8216811783556001936000926110bd928692908116911617612673565b92506101000a81548163ffffffff021916908363ffffffff160217905550600061111e4630600760009054906101000a900463ffffffff1663ffffffff1686600001518760200151886040015189606001518a608001518b60a00151611ac6565b6005819055835180516006805460ff909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff9092169190911790556007546020860151604080880151606089015160808a015160a08b015193519798507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05976111c3978b978b9763ffffffff9091169691959094909390929091906126e1565b60405180910390a16111de8360400151846060015183611b71565b505050505050505050505050565b6111f4611200565b6111fd81611d6c565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611281576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161052d565b565b60006060808380602001905181019061129c9190612777565b60408051808201825283815260208082018490526000868152600282528381208054855181850281018501909652808652979a509598509396509094929391929083018282801561132357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116112f8575b5050505050905060005b815181101561144d57818181518110611348576113486124c7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663bf2732c7846040518263ffffffff1660e01b81526004016113889190612187565b600060405180830381600087803b1580156113a257600080fd5b505af19250505080156113b3575060015b61143b573d8080156113e1576040519150601f19603f3d011682016040523d82523d6000602084013e6113e6565b606091505b507f116391732f5df106193bda7cedf1728f3b07b62f6cdcdd611c9eeec44efcae5483838151811061141a5761141a6124c7565b602002602001015182604051611431929190612875565b60405180910390a1505b8061144581612538565b91505061132d565b5060008581526003602090815260408083208b845290915290208251839190819061147890826128fb565b5060208281015180516114919260018501920190611eeb565b5090505084887fc8db841f5b2231ccf7190311f440aa197b161e369f3b40b023508160cc555656846040516114c69190612187565b60405180910390a350506004805460089690961c63ffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000909616959095179094555050505050565b600061151f826020612a15565b61152a856020612a15565b61153688610144612a2c565b6115409190612a2c565b61154a9190612a2c565b611555906000612a2c565b90503681146104a7576040517ff7b94f0a0000000000000000000000000000000000000000000000000000000081526004810182905236602482015260440161052d565b60006002826020015183604001516115b19190612a3f565b6115bb9190612a58565b6115c6906001612a3f565b60408051600180825281830190925260ff929092169250600091906020820181803683370190505090508160f81b81600081518110611607576116076124c7565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535086821415806116455750868514155b1561168d576040517fe307bd5700000000000000000000000000000000000000000000000000000000815260048101839052602481018890526044810186905260640161052d565b3360009081526008602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156116d0576116d0612644565b60028111156116e1576116e1612644565b90525090506002816020015160028111156116fe576116fe612644565b1415806117465750600a816000015160ff1681548110611720576117206124c7565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b1561177f576040517f2d0f0c0f00000000000000000000000000000000000000000000000000000000815233600482015260240161052d565b50505060008888604051611794929190612aa1565b6040519081900381206117ab918c90602001612ab1565b6040516020818303038152906040528051906020012090506117cb611f26565b604080518082019091526000808252602082015260005b88811015611a20576000600185888460208110611801576118016124c7565b61180e91901a601b612a3f565b8d8d86818110611820576118206124c7565b905060200201358c8c87818110611839576118396124c7565b9050602002013560405160008152602001604052604051611876949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611898573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526008602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561191857611918612644565b600281111561192957611929612644565b905250925060018360200151600281111561194657611946612644565b14611995576040517fbf18af4300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161052d565b8251849060ff16601f81106119ac576119ac6124c7565b6020020151156119e8576040517f21cf3b4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600184846000015160ff16601f8110611a0357611a036124c7565b911515602090920201525080611a1881612538565b9150506117e2565b50505050505050505050505050565b60004661a4b1811480611a44575062066eed81145b15611abf57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab99190612ac5565b91505090565b4391505090565b6000808a8a8a8a8a8a8a8a8a604051602001611aea99989796959493929190612ade565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b6000808351602014611bbc5783516040517f1625adfe00000000000000000000000000000000000000000000000000000000815260206004820152602481019190915260440161052d565b60208401519150808203611bfc576040517faf5e77d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152606080825260208201526000838152600360209081526040808320878452909152902081518291908190611c3a90826128fb565b506020828101518051611c539260018501920190611eeb565b505050600083815260026020908152604080832080548251818502810185019093528083529192909190830182828015611cc357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611c98575b5050505050905060005b8151811015611d6257818181518110611ce857611ce86124c7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166355e487496040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611d3757600080fd5b505af1158015611d4b573d6000803e3d6000fd5b505050508080611d5a90612538565b915050611ccd565b5050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161052d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215611edb579160200282015b82811115611edb57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190611e81565b50611ee7929150611f45565b5090565b828054828255906000526020600020908101928215611edb579160200282015b82811115611edb578251825591602001919060010190611f0b565b604051806103e00160405280601f906020820280368337509192915050565b5b80821115611ee75760008155600101611f46565b60005b83811015611f75578181015183820152602001611f5d565b50506000910152565b60008151808452611f96816020860160208601611f5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611fdb6020830184611f7e565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146111fd57600080fd5b6000806040838503121561201757600080fd5b82359150602083013561202981611fe2565b809150509250929050565b60008083601f84011261204657600080fd5b50813567ffffffffffffffff81111561205e57600080fd5b6020830191508360208260051b850101111561207957600080fd5b9250929050565b60008060008060008060008060e0898b03121561209c57600080fd5b606089018a8111156120ad57600080fd5b8998503567ffffffffffffffff808211156120c757600080fd5b818b0191508b601f8301126120db57600080fd5b8135818111156120ea57600080fd5b8c60208285010111156120fc57600080fd5b6020830199508098505060808b013591508082111561211a57600080fd5b6121268c838d01612034565b909750955060a08b013591508082111561213f57600080fd5b5061214c8b828c01612034565b999c989b50969995989497949560c00135949350505050565b6000806040838503121561217857600080fd5b50508035926020909101359150565b6000602080835283516040828501526121a36060850182611f7e565b858301518582037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0016040870152805180835290840192506000918401905b8083101561220257835182529284019260019290920191908401906121e2565b509695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156122835761228361220d565b604052919050565b600067ffffffffffffffff8211156122a5576122a561220d565b5060051b60200190565b600082601f8301126122c057600080fd5b813560206122d56122d08361228b565b61223c565b82815260059290921b840181019181810190868411156122f457600080fd5b8286015b8481101561220257803561230b81611fe2565b83529183019183016122f8565b803560ff8116811461232957600080fd5b919050565b600067ffffffffffffffff8211156123485761234861220d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261238557600080fd5b81356123936122d08261232e565b8181528460208386010111156123a857600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff8116811461232957600080fd5b60008060008060008060c087890312156123f657600080fd5b863567ffffffffffffffff8082111561240e57600080fd5b61241a8a838b016122af565b9750602089013591508082111561243057600080fd5b61243c8a838b016122af565b965061244a60408a01612318565b9550606089013591508082111561246057600080fd5b61246c8a838b01612374565b945061247a60808a016123c5565b935060a089013591508082111561249057600080fd5b5061249d89828a01612374565b9150509295509295509295565b6000602082840312156124bc57600080fd5b8135611fdb81611fe2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610884576108846124f6565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612569576125696124f6565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600181811c908216806125b357607f821691505b6020821081036125ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60ff818116838216029081169081811461260e5761260e6124f6565b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b63ffffffff81811683821601908082111561260e5761260e6124f6565b600081518084526020808501945080840160005b838110156126d657815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016126a4565b509495945050505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526127118184018a612690565b905082810360808401526127258189612690565b905060ff871660a084015282810360c08401526127428187611f7e565b905067ffffffffffffffff851660e08401528281036101008401526127678185611f7e565b9c9b505050505050505050505050565b60008060006060848603121561278c57600080fd5b8351925060208085015167ffffffffffffffff808211156127ac57600080fd5b818701915087601f8301126127c057600080fd5b81516127ce6122d08261232e565b81815289858386010111156127e257600080fd5b6127f182868301878701611f5a565b60408901519096509250508082111561280957600080fd5b508501601f8101871361281b57600080fd5b80516128296122d08261228b565b81815260059190911b8201830190838101908983111561284857600080fd5b928401925b828410156128665783518252928401929084019061284d565b80955050505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006128a46040830184611f7e565b949350505050565b601f8211156128f657600081815260208120601f850160051c810160208610156128d35750805b601f850160051c820191505b818110156128f2578281556001016128df565b5050505b505050565b815167ffffffffffffffff8111156129155761291561220d565b61292981612923845461259f565b846128ac565b602080601f83116001811461297c57600084156129465750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556128f2565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156129c9578886015182559484019460019091019084016129aa565b5085821015612a0557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8082028115828204841417610884576108846124f6565b80820180821115610884576108846124f6565b60ff8181168382160190811115610884576108846124f6565b600060ff831680612a92577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b8183823760009101908152919050565b828152606082602083013760800192915050565b600060208284031215612ad757600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152612b258285018b612690565b91508382036080850152612b39828a612690565b915060ff881660a085015283820360c0850152612b568288611f7e565b90861660e085015283810361010085015290506127678185611f7e56fea164736f6c6343000813000a", -} - -var DKGABI = DKGMetaData.ABI - -var DKGBin = DKGMetaData.Bin - -func DeployDKG(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *DKG, error) { - parsed, err := DKGMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DKGBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &DKG{DKGCaller: DKGCaller{contract: contract}, DKGTransactor: DKGTransactor{contract: contract}, DKGFilterer: DKGFilterer{contract: contract}}, nil -} - -type DKG struct { - address common.Address - abi abi.ABI - DKGCaller - DKGTransactor - DKGFilterer -} - -type DKGCaller struct { - contract *bind.BoundContract -} - -type DKGTransactor struct { - contract *bind.BoundContract -} - -type DKGFilterer struct { - contract *bind.BoundContract -} - -type DKGSession struct { - Contract *DKG - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type DKGCallerSession struct { - Contract *DKGCaller - CallOpts bind.CallOpts -} - -type DKGTransactorSession struct { - Contract *DKGTransactor - TransactOpts bind.TransactOpts -} - -type DKGRaw struct { - Contract *DKG -} - -type DKGCallerRaw struct { - Contract *DKGCaller -} - -type DKGTransactorRaw struct { - Contract *DKGTransactor -} - -func NewDKG(address common.Address, backend bind.ContractBackend) (*DKG, error) { - abi, err := abi.JSON(strings.NewReader(DKGABI)) - if err != nil { - return nil, err - } - contract, err := bindDKG(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &DKG{address: address, abi: abi, DKGCaller: DKGCaller{contract: contract}, DKGTransactor: DKGTransactor{contract: contract}, DKGFilterer: DKGFilterer{contract: contract}}, nil -} - -func NewDKGCaller(address common.Address, caller bind.ContractCaller) (*DKGCaller, error) { - contract, err := bindDKG(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &DKGCaller{contract: contract}, nil -} - -func NewDKGTransactor(address common.Address, transactor bind.ContractTransactor) (*DKGTransactor, error) { - contract, err := bindDKG(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &DKGTransactor{contract: contract}, nil -} - -func NewDKGFilterer(address common.Address, filterer bind.ContractFilterer) (*DKGFilterer, error) { - contract, err := bindDKG(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &DKGFilterer{contract: contract}, nil -} - -func bindDKG(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := DKGMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_DKG *DKGRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DKG.Contract.DKGCaller.contract.Call(opts, result, method, params...) -} - -func (_DKG *DKGRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DKG.Contract.DKGTransactor.contract.Transfer(opts) -} - -func (_DKG *DKGRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DKG.Contract.DKGTransactor.contract.Transact(opts, method, params...) -} - -func (_DKG *DKGCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DKG.Contract.contract.Call(opts, result, method, params...) -} - -func (_DKG *DKGTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DKG.Contract.contract.Transfer(opts) -} - -func (_DKG *DKGTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DKG.Contract.contract.Transact(opts, method, params...) -} - -func (_DKG *DKGCaller) GetKey(opts *bind.CallOpts, _keyID [32]byte, _configDigest [32]byte) (KeyDataStructKeyData, error) { - var out []interface{} - err := _DKG.contract.Call(opts, &out, "getKey", _keyID, _configDigest) - - if err != nil { - return *new(KeyDataStructKeyData), err - } - - out0 := *abi.ConvertType(out[0], new(KeyDataStructKeyData)).(*KeyDataStructKeyData) - - return out0, err - -} - -func (_DKG *DKGSession) GetKey(_keyID [32]byte, _configDigest [32]byte) (KeyDataStructKeyData, error) { - return _DKG.Contract.GetKey(&_DKG.CallOpts, _keyID, _configDigest) -} - -func (_DKG *DKGCallerSession) GetKey(_keyID [32]byte, _configDigest [32]byte) (KeyDataStructKeyData, error) { - return _DKG.Contract.GetKey(&_DKG.CallOpts, _keyID, _configDigest) -} - -func (_DKG *DKGCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, - - error) { - var out []interface{} - err := _DKG.contract.Call(opts, &out, "latestConfigDetails") - - outstruct := new(LatestConfigDetails) - if err != nil { - return *outstruct, err - } - - outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) - outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) - - return *outstruct, err - -} - -func (_DKG *DKGSession) LatestConfigDetails() (LatestConfigDetails, - - error) { - return _DKG.Contract.LatestConfigDetails(&_DKG.CallOpts) -} - -func (_DKG *DKGCallerSession) LatestConfigDetails() (LatestConfigDetails, - - error) { - return _DKG.Contract.LatestConfigDetails(&_DKG.CallOpts) -} - -func (_DKG *DKGCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, - - error) { - var out []interface{} - err := _DKG.contract.Call(opts, &out, "latestConfigDigestAndEpoch") - - outstruct := new(LatestConfigDigestAndEpoch) - if err != nil { - return *outstruct, err - } - - outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) - - return *outstruct, err - -} - -func (_DKG *DKGSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, - - error) { - return _DKG.Contract.LatestConfigDigestAndEpoch(&_DKG.CallOpts) -} - -func (_DKG *DKGCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, - - error) { - return _DKG.Contract.LatestConfigDigestAndEpoch(&_DKG.CallOpts) -} - -func (_DKG *DKGCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _DKG.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_DKG *DKGSession) Owner() (common.Address, error) { - return _DKG.Contract.Owner(&_DKG.CallOpts) -} - -func (_DKG *DKGCallerSession) Owner() (common.Address, error) { - return _DKG.Contract.Owner(&_DKG.CallOpts) -} - -func (_DKG *DKGCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _DKG.contract.Call(opts, &out, "typeAndVersion") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -func (_DKG *DKGSession) TypeAndVersion() (string, error) { - return _DKG.Contract.TypeAndVersion(&_DKG.CallOpts) -} - -func (_DKG *DKGCallerSession) TypeAndVersion() (string, error) { - return _DKG.Contract.TypeAndVersion(&_DKG.CallOpts) -} - -func (_DKG *DKGTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "acceptOwnership") -} - -func (_DKG *DKGSession) AcceptOwnership() (*types.Transaction, error) { - return _DKG.Contract.AcceptOwnership(&_DKG.TransactOpts) -} - -func (_DKG *DKGTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _DKG.Contract.AcceptOwnership(&_DKG.TransactOpts) -} - -func (_DKG *DKGTransactor) AddClient(opts *bind.TransactOpts, keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "addClient", keyID, clientAddress) -} - -func (_DKG *DKGSession) AddClient(keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.Contract.AddClient(&_DKG.TransactOpts, keyID, clientAddress) -} - -func (_DKG *DKGTransactorSession) AddClient(keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.Contract.AddClient(&_DKG.TransactOpts, keyID, clientAddress) -} - -func (_DKG *DKGTransactor) RemoveClient(opts *bind.TransactOpts, keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "removeClient", keyID, clientAddress) -} - -func (_DKG *DKGSession) RemoveClient(keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.Contract.RemoveClient(&_DKG.TransactOpts, keyID, clientAddress) -} - -func (_DKG *DKGTransactorSession) RemoveClient(keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) { - return _DKG.Contract.RemoveClient(&_DKG.TransactOpts, keyID, clientAddress) -} - -func (_DKG *DKGTransactor) SetConfig(opts *bind.TransactOpts, _signers []common.Address, _transmitters []common.Address, _f uint8, _onchainConfig []byte, _offchainConfigVersion uint64, _offchainConfig []byte) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "setConfig", _signers, _transmitters, _f, _onchainConfig, _offchainConfigVersion, _offchainConfig) -} - -func (_DKG *DKGSession) SetConfig(_signers []common.Address, _transmitters []common.Address, _f uint8, _onchainConfig []byte, _offchainConfigVersion uint64, _offchainConfig []byte) (*types.Transaction, error) { - return _DKG.Contract.SetConfig(&_DKG.TransactOpts, _signers, _transmitters, _f, _onchainConfig, _offchainConfigVersion, _offchainConfig) -} - -func (_DKG *DKGTransactorSession) SetConfig(_signers []common.Address, _transmitters []common.Address, _f uint8, _onchainConfig []byte, _offchainConfigVersion uint64, _offchainConfig []byte) (*types.Transaction, error) { - return _DKG.Contract.SetConfig(&_DKG.TransactOpts, _signers, _transmitters, _f, _onchainConfig, _offchainConfigVersion, _offchainConfig) -} - -func (_DKG *DKGTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "transferOwnership", to) -} - -func (_DKG *DKGSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _DKG.Contract.TransferOwnership(&_DKG.TransactOpts, to) -} - -func (_DKG *DKGTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _DKG.Contract.TransferOwnership(&_DKG.TransactOpts, to) -} - -func (_DKG *DKGTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _DKG.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs) -} - -func (_DKG *DKGSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _DKG.Contract.Transmit(&_DKG.TransactOpts, reportContext, report, rs, ss, rawVs) -} - -func (_DKG *DKGTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _DKG.Contract.Transmit(&_DKG.TransactOpts, reportContext, report, rs, ss, rawVs) -} - -type DKGConfigSetIterator struct { - Event *DKGConfigSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGConfigSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGConfigSet) - 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(DKGConfigSet) - 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 *DKGConfigSetIterator) Error() error { - return it.fail -} - -func (it *DKGConfigSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGConfigSet struct { - PreviousConfigBlockNumber uint32 - ConfigDigest [32]byte - ConfigCount uint64 - Signers []common.Address - Transmitters []common.Address - F uint8 - OnchainConfig []byte - OffchainConfigVersion uint64 - OffchainConfig []byte - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterConfigSet(opts *bind.FilterOpts) (*DKGConfigSetIterator, error) { - - logs, sub, err := _DKG.contract.FilterLogs(opts, "ConfigSet") - if err != nil { - return nil, err - } - return &DKGConfigSetIterator{contract: _DKG.contract, event: "ConfigSet", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *DKGConfigSet) (event.Subscription, error) { - - logs, sub, err := _DKG.contract.WatchLogs(opts, "ConfigSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGConfigSet) - if err := _DKG.contract.UnpackLog(event, "ConfigSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_DKG *DKGFilterer) ParseConfigSet(log types.Log) (*DKGConfigSet, error) { - event := new(DKGConfigSet) - if err := _DKG.contract.UnpackLog(event, "ConfigSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type DKGDKGClientErrorIterator struct { - Event *DKGDKGClientError - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGDKGClientErrorIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGDKGClientError) - 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(DKGDKGClientError) - 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 *DKGDKGClientErrorIterator) Error() error { - return it.fail -} - -func (it *DKGDKGClientErrorIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGDKGClientError struct { - Client common.Address - ErrorData []byte - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterDKGClientError(opts *bind.FilterOpts) (*DKGDKGClientErrorIterator, error) { - - logs, sub, err := _DKG.contract.FilterLogs(opts, "DKGClientError") - if err != nil { - return nil, err - } - return &DKGDKGClientErrorIterator{contract: _DKG.contract, event: "DKGClientError", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchDKGClientError(opts *bind.WatchOpts, sink chan<- *DKGDKGClientError) (event.Subscription, error) { - - logs, sub, err := _DKG.contract.WatchLogs(opts, "DKGClientError") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGDKGClientError) - if err := _DKG.contract.UnpackLog(event, "DKGClientError", 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 (_DKG *DKGFilterer) ParseDKGClientError(log types.Log) (*DKGDKGClientError, error) { - event := new(DKGDKGClientError) - if err := _DKG.contract.UnpackLog(event, "DKGClientError", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type DKGKeyGeneratedIterator struct { - Event *DKGKeyGenerated - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGKeyGeneratedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGKeyGenerated) - 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(DKGKeyGenerated) - 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 *DKGKeyGeneratedIterator) Error() error { - return it.fail -} - -func (it *DKGKeyGeneratedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGKeyGenerated struct { - ConfigDigest [32]byte - KeyID [32]byte - Key KeyDataStructKeyData - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterKeyGenerated(opts *bind.FilterOpts, configDigest [][32]byte, keyID [][32]byte) (*DKGKeyGeneratedIterator, error) { - - var configDigestRule []interface{} - for _, configDigestItem := range configDigest { - configDigestRule = append(configDigestRule, configDigestItem) - } - var keyIDRule []interface{} - for _, keyIDItem := range keyID { - keyIDRule = append(keyIDRule, keyIDItem) - } - - logs, sub, err := _DKG.contract.FilterLogs(opts, "KeyGenerated", configDigestRule, keyIDRule) - if err != nil { - return nil, err - } - return &DKGKeyGeneratedIterator{contract: _DKG.contract, event: "KeyGenerated", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchKeyGenerated(opts *bind.WatchOpts, sink chan<- *DKGKeyGenerated, configDigest [][32]byte, keyID [][32]byte) (event.Subscription, error) { - - var configDigestRule []interface{} - for _, configDigestItem := range configDigest { - configDigestRule = append(configDigestRule, configDigestItem) - } - var keyIDRule []interface{} - for _, keyIDItem := range keyID { - keyIDRule = append(keyIDRule, keyIDItem) - } - - logs, sub, err := _DKG.contract.WatchLogs(opts, "KeyGenerated", configDigestRule, keyIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGKeyGenerated) - if err := _DKG.contract.UnpackLog(event, "KeyGenerated", 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 (_DKG *DKGFilterer) ParseKeyGenerated(log types.Log) (*DKGKeyGenerated, error) { - event := new(DKGKeyGenerated) - if err := _DKG.contract.UnpackLog(event, "KeyGenerated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type DKGOwnershipTransferRequestedIterator struct { - Event *DKGOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGOwnershipTransferRequested) - 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(DKGOwnershipTransferRequested) - 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 *DKGOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *DKGOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DKGOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _DKG.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &DKGOwnershipTransferRequestedIterator{contract: _DKG.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DKGOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _DKG.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGOwnershipTransferRequested) - if err := _DKG.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_DKG *DKGFilterer) ParseOwnershipTransferRequested(log types.Log) (*DKGOwnershipTransferRequested, error) { - event := new(DKGOwnershipTransferRequested) - if err := _DKG.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type DKGOwnershipTransferredIterator struct { - Event *DKGOwnershipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGOwnershipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGOwnershipTransferred) - 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(DKGOwnershipTransferred) - 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 *DKGOwnershipTransferredIterator) Error() error { - return it.fail -} - -func (it *DKGOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DKGOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _DKG.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &DKGOwnershipTransferredIterator{contract: _DKG.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DKGOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _DKG.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGOwnershipTransferred) - if err := _DKG.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_DKG *DKGFilterer) ParseOwnershipTransferred(log types.Log) (*DKGOwnershipTransferred, error) { - event := new(DKGOwnershipTransferred) - if err := _DKG.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type DKGTransmittedIterator struct { - Event *DKGTransmitted - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *DKGTransmittedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(DKGTransmitted) - 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(DKGTransmitted) - 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 *DKGTransmittedIterator) Error() error { - return it.fail -} - -func (it *DKGTransmittedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type DKGTransmitted struct { - ConfigDigest [32]byte - Epoch uint32 - Raw types.Log -} - -func (_DKG *DKGFilterer) FilterTransmitted(opts *bind.FilterOpts) (*DKGTransmittedIterator, error) { - - logs, sub, err := _DKG.contract.FilterLogs(opts, "Transmitted") - if err != nil { - return nil, err - } - return &DKGTransmittedIterator{contract: _DKG.contract, event: "Transmitted", logs: logs, sub: sub}, nil -} - -func (_DKG *DKGFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *DKGTransmitted) (event.Subscription, error) { - - logs, sub, err := _DKG.contract.WatchLogs(opts, "Transmitted") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(DKGTransmitted) - if err := _DKG.contract.UnpackLog(event, "Transmitted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_DKG *DKGFilterer) ParseTransmitted(log types.Log) (*DKGTransmitted, error) { - event := new(DKGTransmitted) - if err := _DKG.contract.UnpackLog(event, "Transmitted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type LatestConfigDetails struct { - ConfigCount uint32 - BlockNumber uint32 - ConfigDigest [32]byte -} -type LatestConfigDigestAndEpoch struct { - ScanLogs bool - ConfigDigest [32]byte - Epoch uint32 -} - -func (_DKG *DKG) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _DKG.abi.Events["ConfigSet"].ID: - return _DKG.ParseConfigSet(log) - case _DKG.abi.Events["DKGClientError"].ID: - return _DKG.ParseDKGClientError(log) - case _DKG.abi.Events["KeyGenerated"].ID: - return _DKG.ParseKeyGenerated(log) - case _DKG.abi.Events["OwnershipTransferRequested"].ID: - return _DKG.ParseOwnershipTransferRequested(log) - case _DKG.abi.Events["OwnershipTransferred"].ID: - return _DKG.ParseOwnershipTransferred(log) - case _DKG.abi.Events["Transmitted"].ID: - return _DKG.ParseTransmitted(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (DKGConfigSet) Topic() common.Hash { - return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") -} - -func (DKGDKGClientError) Topic() common.Hash { - return common.HexToHash("0x116391732f5df106193bda7cedf1728f3b07b62f6cdcdd611c9eeec44efcae54") -} - -func (DKGKeyGenerated) Topic() common.Hash { - return common.HexToHash("0xc8db841f5b2231ccf7190311f440aa197b161e369f3b40b023508160cc555656") -} - -func (DKGOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (DKGOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") -} - -func (DKGTransmitted) Topic() common.Hash { - return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") -} - -func (_DKG *DKG) Address() common.Address { - return _DKG.address -} - -type DKGInterface interface { - GetKey(opts *bind.CallOpts, _keyID [32]byte, _configDigest [32]byte) (KeyDataStructKeyData, error) - - LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, - - error) - - LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, - - error) - - Owner(opts *bind.CallOpts) (common.Address, error) - - TypeAndVersion(opts *bind.CallOpts) (string, error) - - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - - AddClient(opts *bind.TransactOpts, keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) - - RemoveClient(opts *bind.TransactOpts, keyID [32]byte, clientAddress common.Address) (*types.Transaction, error) - - SetConfig(opts *bind.TransactOpts, _signers []common.Address, _transmitters []common.Address, _f uint8, _onchainConfig []byte, _offchainConfigVersion uint64, _offchainConfig []byte) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - - Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) - - FilterConfigSet(opts *bind.FilterOpts) (*DKGConfigSetIterator, error) - - WatchConfigSet(opts *bind.WatchOpts, sink chan<- *DKGConfigSet) (event.Subscription, error) - - ParseConfigSet(log types.Log) (*DKGConfigSet, error) - - FilterDKGClientError(opts *bind.FilterOpts) (*DKGDKGClientErrorIterator, error) - - WatchDKGClientError(opts *bind.WatchOpts, sink chan<- *DKGDKGClientError) (event.Subscription, error) - - ParseDKGClientError(log types.Log) (*DKGDKGClientError, error) - - FilterKeyGenerated(opts *bind.FilterOpts, configDigest [][32]byte, keyID [][32]byte) (*DKGKeyGeneratedIterator, error) - - WatchKeyGenerated(opts *bind.WatchOpts, sink chan<- *DKGKeyGenerated, configDigest [][32]byte, keyID [][32]byte) (event.Subscription, error) - - ParseKeyGenerated(log types.Log) (*DKGKeyGenerated, error) - - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DKGOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DKGOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferRequested(log types.Log) (*DKGOwnershipTransferRequested, error) - - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DKGOwnershipTransferredIterator, error) - - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DKGOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferred(log types.Log) (*DKGOwnershipTransferred, error) - - FilterTransmitted(opts *bind.FilterOpts) (*DKGTransmittedIterator, error) - - WatchTransmitted(opts *bind.WatchOpts, sink chan<- *DKGTransmitted) (event.Subscription, error) - - ParseTransmitted(log types.Log) (*DKGTransmitted, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/ocr2vrf/generated/load_test_beacon_consumer/load_test_beacon_consumer.go b/core/gethwrappers/ocr2vrf/generated/load_test_beacon_consumer/load_test_beacon_consumer.go deleted file mode 100644 index 32bf1e66219..00000000000 --- a/core/gethwrappers/ocr2vrf/generated/load_test_beacon_consumer/load_test_beacon_consumer.go +++ /dev/null @@ -1,1422 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package load_test_beacon_consumer - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -var LoadTestBeaconVRFConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"shouldFail\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"beaconPeriodBlocks\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"MustBeCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeOwnerOrCoordinator\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fail\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"reqID\",\"type\":\"uint256\"}],\"name\":\"getFulfillmentDurationByRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"reqID\",\"type\":\"uint256\"}],\"name\":\"getRawFulfillmentDurationByRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_beaconPeriodBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingRequests\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"requestHeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_ReceivedRandomnessByRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_arguments\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_fulfillmentDurationInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_mostRecentRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_myBeaconRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"slotNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_rawFulfillmentDurationInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestIDs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestOutputHeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"s_requestsIDs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_resetCounter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalFulfilled\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalRequests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"shouldFail\",\"type\":\"bool\"}],\"name\":\"setFail\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"reqId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"delay\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"}],\"name\":\"storeBeaconRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"}],\"name\":\"testRedeemRandomness\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelayArg\",\"type\":\"uint24\"}],\"name\":\"testRequestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"}],\"name\":\"testRequestRandomnessFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelayArg\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"batchSize\",\"type\":\"uint256\"}],\"name\":\"testRequestRandomnessFulfillmentBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040526000600d556000600e556103e7600f556000601055600060115560006012553480156200003057600080fd5b5060405162001f6138038062001f618339810160408190526200005391620001d0565b828282823380600081620000ae5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e157620000e18162000125565b5050600280546001600160a01b0319166001600160a01b03939093169290921790915550600b805460ff191692151592909217909155600c55506200022792505050565b336001600160a01b038216036200017f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a5565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080600060608486031215620001e657600080fd5b83516001600160a01b0381168114620001fe57600080fd5b602085015190935080151581146200021557600080fd5b80925050604084015190509250925092565b611d2a80620002376000396000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c806379ba509711610160578063d0705f04116100d8578063f2fde38b1161008c578063f6eaffc811610071578063f6eaffc8146105bc578063fc7fea37146105cf578063ffe97ca4146105d857600080fd5b8063f2fde38b1461057e578063f371829b1461059157600080fd5b8063d826f88f116100bd578063d826f88f1461055a578063ea7502ab14610562578063f08c5daa1461057557600080fd5b8063d0705f0414610534578063d21ea8fd1461054757600080fd5b80638ea981171161012f578063a9cc471811610114578063a9cc4718146104fb578063c6d6130114610518578063cd0593df1461052b57600080fd5b80638ea98117146104a95780639d769402146104bc57600080fd5b806379ba5097146104675780638866c6bd1461046f5780638d0e3165146104785780638da5cb5b1461048157600080fd5b80635a947873116101f35780636df57cc3116101c2578063737144bc116101a7578063737144bc1461044057806374dba124146104495780637716cdaa1461045257600080fd5b80636df57cc314610400578063706da1ca1461041357600080fd5b80635a947873146103b05780635f15cccc146103c3578063601201d3146103ee578063689b77ab146103f757600080fd5b80632b1a21301161024a578063341867a21161022f578063341867a21461035b578063353e0f60146103705780634a0aee291461039b57600080fd5b80632b1a21301461031d5780632fe8fa311461033057600080fd5b80631591950a1461027c5780631757f11c146102ba578063195e0d75146102c35780631e87f20e146102f0575b600080fd5b6102a761028a366004611503565b601560209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6102a7600e5481565b6102a76102d1366004611525565b6012546000908152601860209081526040808320938352929052205490565b6102a76102fe366004611525565b6012546000908152601760209081526040808320938352929052205490565b6102a761032b366004611503565b61068b565b6102a761033e366004611503565b601760209081526000928352604080842090915290825290205481565b61036e610369366004611503565b6106bc565b005b6102a761037e366004611503565b601660209081526000928352604080842090915290825290205481565b6103a36107b1565b6040516102b1919061153e565b6103a36103be3660046116cc565b6108c1565b6102a76103d136600461174d565b600460209081526000928352604080842090915290825290205481565b6102a760115481565b6102a760085481565b61036e61040e366004611779565b610a1f565b6009546104279067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016102b1565b6102a7600d5481565b6102a7600f5481565b61045a610b5a565b6040516102b19190611823565b61036e610be8565b6102a760105481565b6102a760135481565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b1565b61036e6104b736600461183d565b610cea565b61036e6104ca366004611873565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b600b546105089060ff1681565b60405190151581526020016102b1565b6102a7610526366004611895565b610dd0565b6102a7600c5481565b6102a7610542366004611503565b610eda565b61036e6105553660046118f5565b610ef6565b61036e610f57565b6102a76105703660046119be565b610f8d565b6102a7600a5481565b61036e61058c36600461183d565b61109d565b6102a761059f366004611503565b601860209081526000928352604080842090915290825290205481565b6102a76105ca366004611525565b6110b1565b6102a760125481565b6106416105e6366004611525565b60056020526000908152604090205463ffffffff811690640100000000810462ffffff1690670100000000000000810461ffff16906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1684565b6040805163ffffffff909516855262ffffff909316602085015261ffff9091169183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080016102b1565b601460205281600052604060002081815481106106a757600080fd5b90600052602060002001600091509150505481565b60025460408051602081018252600080825291517facfc6cdd000000000000000000000000000000000000000000000000000000008152919273ffffffffffffffffffffffffffffffffffffffff169163acfc6cdd916107229187918791600401611a37565b6000604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107879190810190611a5f565b600083815260066020908152604090912082519293506107ab9290918401906114a3565b50505050565b6012546000908152601460205260408120546060919067ffffffffffffffff8111156107df576107df6115c0565b604051908082528060200260200182016040528015610808578160200160208202803683370190505b5090506000805b6012546000908152601460205260409020548110156108b957601254600090815260146020526040812080548390811061084b5761084b611af0565b600091825260208083209091015460125483526017825260408084208285529092529082205490925090036108a6578084848151811061088d5761088d611af0565b6020908102919091010152826108a281611b4e565b9350505b50806108b181611b4e565b91505061080f565b508152919050565b606060008267ffffffffffffffff8111156108de576108de6115c0565b604051908082528060200260200182016040528015610907578160200160208202803683370190505b5090506000600c546109176110d2565b6109219190611bb5565b9050600081600c546109316110d2565b61093b9190611bc9565b6109459190611be2565b905060005b85811015610a105760006109618c8c8c8c8c610f8d565b60108054919250600061097383611b4e565b90915550506012546000908152601560209081526040808320848452909152902083905561099f6110d2565b60128054600090815260166020908152604080832086845282528083209490945591548152601482529182208054600181018255908352912001819055845181908690849081106109f2576109f2611af0565b60209081029190910101525080610a0881611b4e565b91505061094a565b50919998505050505050505050565b600083815260046020908152604080832062ffffff861684529091528120859055600c54610a4d9085611bf5565b6040805160808101825263ffffffff928316815262ffffff958616602080830191825261ffff968716838501908152306060850190815260009b8c526005909252939099209151825491519351995173ffffffffffffffffffffffffffffffffffffffff166901000000000000000000027fffffff0000000000000000000000000000000000000000ffffffffffffffffff9a90971667010000000000000002999099167fffffff00000000000000000000000000000000000000000000ffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009091169890931697909717919091171692909217179092555050565b60078054610b6790611c09565b80601f0160208091040260200160405190810160405280929190818152602001828054610b9390611c09565b8015610be05780601f10610bb557610100808354040283529160200191610be0565b820191906000526020600020905b815481529060010190602001808311610bc357829003601f168201915b505050505081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610d2a575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610d61576040517fd4e06fd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fc258faa9a17ddfdf4130b4acff63a289202e7d5f9e42f366add65368575486bc90600090a250565b600080600c54610dde6110d2565b610de89190611bb5565b9050600081600c54610df86110d2565b610e029190611bc9565b610e0c9190611be2565b60025460408051602081018252600080825291517f4ffac83a000000000000000000000000000000000000000000000000000000008152939450909273ffffffffffffffffffffffffffffffffffffffff90921691634ffac83a91610e7a918a918c918b9190600401611c5c565b6020604051808303816000875af1158015610e99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebd9190611c94565b9050610ecb8183878a610a1f565b60088190559695505050505050565b600660205281600052604060002081815481106106a757600080fd5b60025473ffffffffffffffffffffffffffffffffffffffff163314610f47576040517f66bf9c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f52838383611169565b505050565b6000600d819055600e8190556103e7600f556010819055601181905560138190556012805491610f8683611b4e565b9190505550565b600080600c54610f9b6110d2565b610fa59190611bb5565b9050600081600c54610fb56110d2565b610fbf9190611bc9565b610fc99190611be2565b60025460408051602081018252600080825291517fdb972c8b000000000000000000000000000000000000000000000000000000008152939450909273ffffffffffffffffffffffffffffffffffffffff9092169163db972c8b9161103b918d918d918d918d918d9190600401611cad565b6020604051808303816000875af115801561105a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107e9190611c94565b905061108c8183898b610a1f565b600881905598975050505050505050565b6110a561132b565b6110ae816113ae565b50565b600381815481106110c157600080fd5b600091825260209091200154905081565b60004661a4b18114806110e7575062066eed81145b1561116257606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611138573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115c9190611c94565b91505090565b4391505090565b600b5460ff16156111d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f206661696c656420696e2066756c66696c6c52616e646f6d576f7264730000006044820152606401610c65565b600083815260066020908152604090912083516111f5928501906114a3565b50601254600090815260156020908152604080832086845290915281205461121b6110d2565b6112259190611be2565b60125460009081526016602090815260408083208884529091528120549192509061124e6110d2565b6112589190611be2565b9050600061126983620f4240611d06565b9050600e5483111561128057600e83905560138690555b600f54831061129157600f54611293565b825b600f556011546112a357806112d6565b6011546112b1906001611bc9565b81601154600d546112c29190611d06565b6112cc9190611bc9565b6112d69190611bf5565b600d55601180549060006112e983611b4e565b90915550506012805460009081526017602090815260408083208a84528252808320969096559154815260188252848120978152969052509320929092555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146113ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c65565b565b3373ffffffffffffffffffffffffffffffffffffffff82160361142d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c65565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b8280548282559060005260206000209081019282156114de579160200282015b828111156114de5782518255916020019190600101906114c3565b506114ea9291506114ee565b5090565b5b808211156114ea57600081556001016114ef565b6000806040838503121561151657600080fd5b50508035926020909101359150565b60006020828403121561153757600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156115765783518352928401929184019160010161155a565b50909695505050505050565b803561ffff8116811461159457600080fd5b919050565b803562ffffff8116811461159457600080fd5b803563ffffffff8116811461159457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611636576116366115c0565b604052919050565b600082601f83011261164f57600080fd5b813567ffffffffffffffff811115611669576116696115c0565b61169a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016115ef565b8181528460208386010111156116af57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156116e557600080fd5b863595506116f560208801611582565b945061170360408801611599565b9350611711606088016115ac565b9250608087013567ffffffffffffffff81111561172d57600080fd5b61173989828a0161163e565b92505060a087013590509295509295509295565b6000806040838503121561176057600080fd5b8235915061177060208401611599565b90509250929050565b6000806000806080858703121561178f57600080fd5b84359350602085013592506117a660408601611599565b91506117b460608601611582565b905092959194509250565b6000815180845260005b818110156117e5576020818501810151868301820152016117c9565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061183660208301846117bf565b9392505050565b60006020828403121561184f57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461183657600080fd5b60006020828403121561188557600080fd5b8135801515811461183657600080fd5b6000806000606084860312156118aa57600080fd5b6118b384611582565b9250602084013591506118c860408501611599565b90509250925092565b600067ffffffffffffffff8211156118eb576118eb6115c0565b5060051b60200190565b60008060006060848603121561190a57600080fd5b8335925060208085013567ffffffffffffffff8082111561192a57600080fd5b818701915087601f83011261193e57600080fd5b813561195161194c826118d1565b6115ef565b81815260059190911b8301840190848101908a83111561197057600080fd5b938501935b8285101561198e57843582529385019390850190611975565b9650505060408701359250808311156119a657600080fd5b50506119b48682870161163e565b9150509250925092565b600080600080600060a086880312156119d657600080fd5b853594506119e660208701611582565b93506119f460408701611599565b9250611a02606087016115ac565b9150608086013567ffffffffffffffff811115611a1e57600080fd5b611a2a8882890161163e565b9150509295509295909350565b838152826020820152606060408201526000611a5660608301846117bf565b95945050505050565b60006020808385031215611a7257600080fd5b825167ffffffffffffffff811115611a8957600080fd5b8301601f81018513611a9a57600080fd5b8051611aa861194c826118d1565b81815260059190911b82018301908381019087831115611ac757600080fd5b928401925b82841015611ae557835182529284019290840190611acc565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611b7f57611b7f611b1f565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082611bc457611bc4611b86565b500690565b80820180821115611bdc57611bdc611b1f565b92915050565b81810381811115611bdc57611bdc611b1f565b600082611c0457611c04611b86565b500490565b600181811c90821680611c1d57607f821691505b602082108103611c56577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b84815261ffff8416602082015262ffffff83166040820152608060608201526000611c8a60808301846117bf565b9695505050505050565b600060208284031215611ca657600080fd5b5051919050565b86815261ffff8616602082015262ffffff8516604082015263ffffffff8416606082015260c060808201526000611ce760c08301856117bf565b82810360a0840152611cf981856117bf565b9998505050505050505050565b8082028115828204841417611bdc57611bdc611b1f56fea164736f6c6343000813000a", -} - -var LoadTestBeaconVRFConsumerABI = LoadTestBeaconVRFConsumerMetaData.ABI - -var LoadTestBeaconVRFConsumerBin = LoadTestBeaconVRFConsumerMetaData.Bin - -func DeployLoadTestBeaconVRFConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, coordinator common.Address, shouldFail bool, beaconPeriodBlocks *big.Int) (common.Address, *types.Transaction, *LoadTestBeaconVRFConsumer, error) { - parsed, err := LoadTestBeaconVRFConsumerMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LoadTestBeaconVRFConsumerBin), backend, coordinator, shouldFail, beaconPeriodBlocks) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &LoadTestBeaconVRFConsumer{LoadTestBeaconVRFConsumerCaller: LoadTestBeaconVRFConsumerCaller{contract: contract}, LoadTestBeaconVRFConsumerTransactor: LoadTestBeaconVRFConsumerTransactor{contract: contract}, LoadTestBeaconVRFConsumerFilterer: LoadTestBeaconVRFConsumerFilterer{contract: contract}}, nil -} - -type LoadTestBeaconVRFConsumer struct { - address common.Address - abi abi.ABI - LoadTestBeaconVRFConsumerCaller - LoadTestBeaconVRFConsumerTransactor - LoadTestBeaconVRFConsumerFilterer -} - -type LoadTestBeaconVRFConsumerCaller struct { - contract *bind.BoundContract -} - -type LoadTestBeaconVRFConsumerTransactor struct { - contract *bind.BoundContract -} - -type LoadTestBeaconVRFConsumerFilterer struct { - contract *bind.BoundContract -} - -type LoadTestBeaconVRFConsumerSession struct { - Contract *LoadTestBeaconVRFConsumer - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type LoadTestBeaconVRFConsumerCallerSession struct { - Contract *LoadTestBeaconVRFConsumerCaller - CallOpts bind.CallOpts -} - -type LoadTestBeaconVRFConsumerTransactorSession struct { - Contract *LoadTestBeaconVRFConsumerTransactor - TransactOpts bind.TransactOpts -} - -type LoadTestBeaconVRFConsumerRaw struct { - Contract *LoadTestBeaconVRFConsumer -} - -type LoadTestBeaconVRFConsumerCallerRaw struct { - Contract *LoadTestBeaconVRFConsumerCaller -} - -type LoadTestBeaconVRFConsumerTransactorRaw struct { - Contract *LoadTestBeaconVRFConsumerTransactor -} - -func NewLoadTestBeaconVRFConsumer(address common.Address, backend bind.ContractBackend) (*LoadTestBeaconVRFConsumer, error) { - abi, err := abi.JSON(strings.NewReader(LoadTestBeaconVRFConsumerABI)) - if err != nil { - return nil, err - } - contract, err := bindLoadTestBeaconVRFConsumer(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumer{address: address, abi: abi, LoadTestBeaconVRFConsumerCaller: LoadTestBeaconVRFConsumerCaller{contract: contract}, LoadTestBeaconVRFConsumerTransactor: LoadTestBeaconVRFConsumerTransactor{contract: contract}, LoadTestBeaconVRFConsumerFilterer: LoadTestBeaconVRFConsumerFilterer{contract: contract}}, nil -} - -func NewLoadTestBeaconVRFConsumerCaller(address common.Address, caller bind.ContractCaller) (*LoadTestBeaconVRFConsumerCaller, error) { - contract, err := bindLoadTestBeaconVRFConsumer(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerCaller{contract: contract}, nil -} - -func NewLoadTestBeaconVRFConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*LoadTestBeaconVRFConsumerTransactor, error) { - contract, err := bindLoadTestBeaconVRFConsumer(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerTransactor{contract: contract}, nil -} - -func NewLoadTestBeaconVRFConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*LoadTestBeaconVRFConsumerFilterer, error) { - contract, err := bindLoadTestBeaconVRFConsumer(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerFilterer{contract: contract}, nil -} - -func bindLoadTestBeaconVRFConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := LoadTestBeaconVRFConsumerMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _LoadTestBeaconVRFConsumer.Contract.LoadTestBeaconVRFConsumerCaller.contract.Call(opts, result, method, params...) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.LoadTestBeaconVRFConsumerTransactor.contract.Transfer(opts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.LoadTestBeaconVRFConsumerTransactor.contract.Transact(opts, method, params...) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _LoadTestBeaconVRFConsumer.Contract.contract.Call(opts, result, method, params...) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.contract.Transfer(opts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.contract.Transact(opts, method, params...) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) Fail(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "fail") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) Fail() (bool, error) { - return _LoadTestBeaconVRFConsumer.Contract.Fail(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) Fail() (bool, error) { - return _LoadTestBeaconVRFConsumer.Contract.Fail(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) GetFulfillmentDurationByRequestID(opts *bind.CallOpts, reqID *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "getFulfillmentDurationByRequestID", reqID) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) GetFulfillmentDurationByRequestID(reqID *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.GetFulfillmentDurationByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, reqID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) GetFulfillmentDurationByRequestID(reqID *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.GetFulfillmentDurationByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, reqID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) GetRawFulfillmentDurationByRequestID(opts *bind.CallOpts, reqID *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "getRawFulfillmentDurationByRequestID", reqID) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) GetRawFulfillmentDurationByRequestID(reqID *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.GetRawFulfillmentDurationByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, reqID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) GetRawFulfillmentDurationByRequestID(reqID *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.GetRawFulfillmentDurationByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, reqID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "i_beaconPeriodBlocks") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.IBeaconPeriodBlocks(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.IBeaconPeriodBlocks(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) Owner() (common.Address, error) { - return _LoadTestBeaconVRFConsumer.Contract.Owner(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) Owner() (common.Address, error) { - return _LoadTestBeaconVRFConsumer.Contract.Owner(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) PendingRequests(opts *bind.CallOpts) ([]*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "pendingRequests") - - if err != nil { - return *new([]*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) PendingRequests() ([]*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.PendingRequests(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) PendingRequests() ([]*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.PendingRequests(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) RequestHeights(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "requestHeights", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) RequestHeights(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.RequestHeights(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) RequestHeights(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.RequestHeights(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SReceivedRandomnessByRequestID(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_ReceivedRandomnessByRequestID", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SReceivedRandomnessByRequestID(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SReceivedRandomnessByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SReceivedRandomnessByRequestID(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SReceivedRandomnessByRequestID(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SArguments(opts *bind.CallOpts) ([]byte, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_arguments") - - if err != nil { - return *new([]byte), err - } - - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SArguments() ([]byte, error) { - return _LoadTestBeaconVRFConsumer.Contract.SArguments(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SArguments() ([]byte, error) { - return _LoadTestBeaconVRFConsumer.Contract.SArguments(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_averageFulfillmentInMillions") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SAverageFulfillmentInMillions() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SAverageFulfillmentInMillions(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SAverageFulfillmentInMillions() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SAverageFulfillmentInMillions(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_fastestFulfillment") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SFastestFulfillment() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SFastestFulfillment(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SFastestFulfillment() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SFastestFulfillment(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SFulfillmentDurationInBlocks(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_fulfillmentDurationInBlocks", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SFulfillmentDurationInBlocks(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SFulfillmentDurationInBlocks(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SFulfillmentDurationInBlocks(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SFulfillmentDurationInBlocks(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SGasAvailable(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_gasAvailable") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SGasAvailable() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SGasAvailable(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SGasAvailable() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SGasAvailable(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SMostRecentRequestID(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_mostRecentRequestID") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SMostRecentRequestID() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SMostRecentRequestID(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SMostRecentRequestID() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SMostRecentRequestID(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SMyBeaconRequests(opts *bind.CallOpts, arg0 *big.Int) (SMyBeaconRequests, - - error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_myBeaconRequests", arg0) - - outstruct := new(SMyBeaconRequests) - if err != nil { - return *outstruct, err - } - - outstruct.SlotNumber = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.ConfirmationDelay = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.NumWords = *abi.ConvertType(out[2], new(uint16)).(*uint16) - outstruct.Requester = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) - - return *outstruct, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SMyBeaconRequests(arg0 *big.Int) (SMyBeaconRequests, - - error) { - return _LoadTestBeaconVRFConsumer.Contract.SMyBeaconRequests(&_LoadTestBeaconVRFConsumer.CallOpts, arg0) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SMyBeaconRequests(arg0 *big.Int) (SMyBeaconRequests, - - error) { - return _LoadTestBeaconVRFConsumer.Contract.SMyBeaconRequests(&_LoadTestBeaconVRFConsumer.CallOpts, arg0) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SRandomWords(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_randomWords", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SRandomWords(arg0 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRandomWords(&_LoadTestBeaconVRFConsumer.CallOpts, arg0) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SRandomWords(arg0 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRandomWords(&_LoadTestBeaconVRFConsumer.CallOpts, arg0) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SRawFulfillmentDurationInBlocks(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_rawFulfillmentDurationInBlocks", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SRawFulfillmentDurationInBlocks(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRawFulfillmentDurationInBlocks(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SRawFulfillmentDurationInBlocks(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRawFulfillmentDurationInBlocks(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SRequestIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_requestIDs", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SRequestIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestIDs(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SRequestIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestIDs(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SRequestOutputHeights(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_requestOutputHeights", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SRequestOutputHeights(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestOutputHeights(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SRequestOutputHeights(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestOutputHeights(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SRequestsIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_requestsIDs", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SRequestsIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestsIDs(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SRequestsIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SRequestsIDs(&_LoadTestBeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SResetCounter(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_resetCounter") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SResetCounter() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SResetCounter(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SResetCounter() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SResetCounter(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_slowestFulfillment") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SSlowestFulfillment() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSlowestFulfillment(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SSlowestFulfillment() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSlowestFulfillment(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SSlowestRequestID(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_slowestRequestID") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SSlowestRequestID() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSlowestRequestID(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SSlowestRequestID() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSlowestRequestID(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) SSubId(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_subId") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SSubId() (uint64, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSubId(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) SSubId() (uint64, error) { - return _LoadTestBeaconVRFConsumer.Contract.SSubId(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) STotalFulfilled(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_totalFulfilled") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) STotalFulfilled() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.STotalFulfilled(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) STotalFulfilled() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.STotalFulfilled(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCaller) STotalRequests(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _LoadTestBeaconVRFConsumer.contract.Call(opts, &out, "s_totalRequests") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) STotalRequests() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.STotalRequests(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerCallerSession) STotalRequests() (*big.Int, error) { - return _LoadTestBeaconVRFConsumer.Contract.STotalRequests(&_LoadTestBeaconVRFConsumer.CallOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "acceptOwnership") -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) AcceptOwnership() (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.AcceptOwnership(&_LoadTestBeaconVRFConsumer.TransactOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.AcceptOwnership(&_LoadTestBeaconVRFConsumer.TransactOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "rawFulfillRandomWords", requestID, randomWords, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) RawFulfillRandomWords(requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.RawFulfillRandomWords(&_LoadTestBeaconVRFConsumer.TransactOpts, requestID, randomWords, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) RawFulfillRandomWords(requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.RawFulfillRandomWords(&_LoadTestBeaconVRFConsumer.TransactOpts, requestID, randomWords, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "reset") -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) Reset() (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.Reset(&_LoadTestBeaconVRFConsumer.TransactOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) Reset() (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.Reset(&_LoadTestBeaconVRFConsumer.TransactOpts) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) SetCoordinator(opts *bind.TransactOpts, coordinator common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "setCoordinator", coordinator) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SetCoordinator(coordinator common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.SetCoordinator(&_LoadTestBeaconVRFConsumer.TransactOpts, coordinator) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) SetCoordinator(coordinator common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.SetCoordinator(&_LoadTestBeaconVRFConsumer.TransactOpts, coordinator) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) SetFail(opts *bind.TransactOpts, shouldFail bool) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "setFail", shouldFail) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) SetFail(shouldFail bool) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.SetFail(&_LoadTestBeaconVRFConsumer.TransactOpts, shouldFail) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) SetFail(shouldFail bool) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.SetFail(&_LoadTestBeaconVRFConsumer.TransactOpts, shouldFail) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) StoreBeaconRequest(opts *bind.TransactOpts, reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "storeBeaconRequest", reqId, height, delay, numWords) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) StoreBeaconRequest(reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.StoreBeaconRequest(&_LoadTestBeaconVRFConsumer.TransactOpts, reqId, height, delay, numWords) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) StoreBeaconRequest(reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.StoreBeaconRequest(&_LoadTestBeaconVRFConsumer.TransactOpts, reqId, height, delay, numWords) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) TestRedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "testRedeemRandomness", subID, requestID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) TestRedeemRandomness(subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRedeemRandomness(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, requestID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) TestRedeemRandomness(subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRedeemRandomness(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, requestID) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) TestRequestRandomness(opts *bind.TransactOpts, numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "testRequestRandomness", numWords, subID, confirmationDelayArg) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) TestRequestRandomness(numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomness(&_LoadTestBeaconVRFConsumer.TransactOpts, numWords, subID, confirmationDelayArg) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) TestRequestRandomness(numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomness(&_LoadTestBeaconVRFConsumer.TransactOpts, numWords, subID, confirmationDelayArg) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) TestRequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "testRequestRandomnessFulfillment", subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) TestRequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomnessFulfillment(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) TestRequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomnessFulfillment(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) TestRequestRandomnessFulfillmentBatch(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confirmationDelayArg *big.Int, callbackGasLimit uint32, arguments []byte, batchSize *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "testRequestRandomnessFulfillmentBatch", subID, numWords, confirmationDelayArg, callbackGasLimit, arguments, batchSize) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) TestRequestRandomnessFulfillmentBatch(subID *big.Int, numWords uint16, confirmationDelayArg *big.Int, callbackGasLimit uint32, arguments []byte, batchSize *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomnessFulfillmentBatch(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, numWords, confirmationDelayArg, callbackGasLimit, arguments, batchSize) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) TestRequestRandomnessFulfillmentBatch(subID *big.Int, numWords uint16, confirmationDelayArg *big.Int, callbackGasLimit uint32, arguments []byte, batchSize *big.Int) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TestRequestRandomnessFulfillmentBatch(&_LoadTestBeaconVRFConsumer.TransactOpts, subID, numWords, confirmationDelayArg, callbackGasLimit, arguments, batchSize) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.contract.Transact(opts, "transferOwnership", to) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TransferOwnership(&_LoadTestBeaconVRFConsumer.TransactOpts, to) -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _LoadTestBeaconVRFConsumer.Contract.TransferOwnership(&_LoadTestBeaconVRFConsumer.TransactOpts, to) -} - -type LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator struct { - Event *LoadTestBeaconVRFConsumerCoordinatorUpdated - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(LoadTestBeaconVRFConsumerCoordinatorUpdated) - 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(LoadTestBeaconVRFConsumerCoordinatorUpdated) - 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 *LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator) Error() error { - return it.fail -} - -func (it *LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type LoadTestBeaconVRFConsumerCoordinatorUpdated struct { - Coordinator common.Address - Raw types.Log -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) FilterCoordinatorUpdated(opts *bind.FilterOpts, coordinator []common.Address) (*LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator, error) { - - var coordinatorRule []interface{} - for _, coordinatorItem := range coordinator { - coordinatorRule = append(coordinatorRule, coordinatorItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.FilterLogs(opts, "CoordinatorUpdated", coordinatorRule) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator{contract: _LoadTestBeaconVRFConsumer.contract, event: "CoordinatorUpdated", logs: logs, sub: sub}, nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) WatchCoordinatorUpdated(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerCoordinatorUpdated, coordinator []common.Address) (event.Subscription, error) { - - var coordinatorRule []interface{} - for _, coordinatorItem := range coordinator { - coordinatorRule = append(coordinatorRule, coordinatorItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.WatchLogs(opts, "CoordinatorUpdated", coordinatorRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(LoadTestBeaconVRFConsumerCoordinatorUpdated) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "CoordinatorUpdated", 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 (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) ParseCoordinatorUpdated(log types.Log) (*LoadTestBeaconVRFConsumerCoordinatorUpdated, error) { - event := new(LoadTestBeaconVRFConsumerCoordinatorUpdated) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "CoordinatorUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator struct { - Event *LoadTestBeaconVRFConsumerOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(LoadTestBeaconVRFConsumerOwnershipTransferRequested) - 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(LoadTestBeaconVRFConsumerOwnershipTransferRequested) - 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 *LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type LoadTestBeaconVRFConsumerOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator{contract: _LoadTestBeaconVRFConsumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(LoadTestBeaconVRFConsumerOwnershipTransferRequested) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*LoadTestBeaconVRFConsumerOwnershipTransferRequested, error) { - event := new(LoadTestBeaconVRFConsumerOwnershipTransferRequested) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type LoadTestBeaconVRFConsumerOwnershipTransferredIterator struct { - Event *LoadTestBeaconVRFConsumerOwnershipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *LoadTestBeaconVRFConsumerOwnershipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(LoadTestBeaconVRFConsumerOwnershipTransferred) - 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(LoadTestBeaconVRFConsumerOwnershipTransferred) - 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 *LoadTestBeaconVRFConsumerOwnershipTransferredIterator) Error() error { - return it.fail -} - -func (it *LoadTestBeaconVRFConsumerOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type LoadTestBeaconVRFConsumerOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LoadTestBeaconVRFConsumerOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &LoadTestBeaconVRFConsumerOwnershipTransferredIterator{contract: _LoadTestBeaconVRFConsumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _LoadTestBeaconVRFConsumer.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(LoadTestBeaconVRFConsumerOwnershipTransferred) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*LoadTestBeaconVRFConsumerOwnershipTransferred, error) { - event := new(LoadTestBeaconVRFConsumerOwnershipTransferred) - if err := _LoadTestBeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type SMyBeaconRequests struct { - SlotNumber uint32 - ConfirmationDelay *big.Int - NumWords uint16 - Requester common.Address -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumer) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _LoadTestBeaconVRFConsumer.abi.Events["CoordinatorUpdated"].ID: - return _LoadTestBeaconVRFConsumer.ParseCoordinatorUpdated(log) - case _LoadTestBeaconVRFConsumer.abi.Events["OwnershipTransferRequested"].ID: - return _LoadTestBeaconVRFConsumer.ParseOwnershipTransferRequested(log) - case _LoadTestBeaconVRFConsumer.abi.Events["OwnershipTransferred"].ID: - return _LoadTestBeaconVRFConsumer.ParseOwnershipTransferred(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (LoadTestBeaconVRFConsumerCoordinatorUpdated) Topic() common.Hash { - return common.HexToHash("0xc258faa9a17ddfdf4130b4acff63a289202e7d5f9e42f366add65368575486bc") -} - -func (LoadTestBeaconVRFConsumerOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (LoadTestBeaconVRFConsumerOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") -} - -func (_LoadTestBeaconVRFConsumer *LoadTestBeaconVRFConsumer) Address() common.Address { - return _LoadTestBeaconVRFConsumer.address -} - -type LoadTestBeaconVRFConsumerInterface interface { - Fail(opts *bind.CallOpts) (bool, error) - - GetFulfillmentDurationByRequestID(opts *bind.CallOpts, reqID *big.Int) (*big.Int, error) - - GetRawFulfillmentDurationByRequestID(opts *bind.CallOpts, reqID *big.Int) (*big.Int, error) - - IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) - - Owner(opts *bind.CallOpts) (common.Address, error) - - PendingRequests(opts *bind.CallOpts) ([]*big.Int, error) - - RequestHeights(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SReceivedRandomnessByRequestID(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SArguments(opts *bind.CallOpts) ([]byte, error) - - SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) - - SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) - - SFulfillmentDurationInBlocks(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SGasAvailable(opts *bind.CallOpts) (*big.Int, error) - - SMostRecentRequestID(opts *bind.CallOpts) (*big.Int, error) - - SMyBeaconRequests(opts *bind.CallOpts, arg0 *big.Int) (SMyBeaconRequests, - - error) - - SRandomWords(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) - - SRawFulfillmentDurationInBlocks(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SRequestIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SRequestOutputHeights(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SRequestsIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SResetCounter(opts *bind.CallOpts) (*big.Int, error) - - SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) - - SSlowestRequestID(opts *bind.CallOpts) (*big.Int, error) - - SSubId(opts *bind.CallOpts) (uint64, error) - - STotalFulfilled(opts *bind.CallOpts) (*big.Int, error) - - STotalRequests(opts *bind.CallOpts) (*big.Int, error) - - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - - RawFulfillRandomWords(opts *bind.TransactOpts, requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) - - Reset(opts *bind.TransactOpts) (*types.Transaction, error) - - SetCoordinator(opts *bind.TransactOpts, coordinator common.Address) (*types.Transaction, error) - - SetFail(opts *bind.TransactOpts, shouldFail bool) (*types.Transaction, error) - - StoreBeaconRequest(opts *bind.TransactOpts, reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) - - TestRedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int) (*types.Transaction, error) - - TestRequestRandomness(opts *bind.TransactOpts, numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) - - TestRequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) - - TestRequestRandomnessFulfillmentBatch(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confirmationDelayArg *big.Int, callbackGasLimit uint32, arguments []byte, batchSize *big.Int) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - - FilterCoordinatorUpdated(opts *bind.FilterOpts, coordinator []common.Address) (*LoadTestBeaconVRFConsumerCoordinatorUpdatedIterator, error) - - WatchCoordinatorUpdated(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerCoordinatorUpdated, coordinator []common.Address) (event.Subscription, error) - - ParseCoordinatorUpdated(log types.Log) (*LoadTestBeaconVRFConsumerCoordinatorUpdated, error) - - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LoadTestBeaconVRFConsumerOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferRequested(log types.Log) (*LoadTestBeaconVRFConsumerOwnershipTransferRequested, error) - - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LoadTestBeaconVRFConsumerOwnershipTransferredIterator, error) - - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LoadTestBeaconVRFConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferred(log types.Log) (*LoadTestBeaconVRFConsumerOwnershipTransferred, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/ocr2vrf/generated/vrf_beacon/vrf_beacon.go b/core/gethwrappers/ocr2vrf/generated/vrf_beacon/vrf_beacon.go deleted file mode 100644 index b44019de548..00000000000 --- a/core/gethwrappers/ocr2vrf/generated/vrf_beacon/vrf_beacon.go +++ /dev/null @@ -1,2846 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package vrf_beacon - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -type ECCArithmeticG1Point struct { - P [2]*big.Int -} - -type KeyDataStructKeyData struct { - PublicKey []byte - Hashes [][32]byte -} - -type VRFBeaconReportReport struct { - Outputs []VRFBeaconTypesVRFOutput - JuelsPerFeeCoin *big.Int - ReasonableGasPrice uint64 - RecentBlockHeight uint64 - RecentBlockHash [32]byte -} - -type VRFBeaconTypesCallback struct { - RequestID *big.Int - NumWords uint16 - Requester common.Address - Arguments []byte - GasAllowance *big.Int - SubID *big.Int - GasPrice *big.Int - WeiPerUnitLink *big.Int -} - -type VRFBeaconTypesCostedCallback struct { - Callback VRFBeaconTypesCallback - Price *big.Int -} - -type VRFBeaconTypesOutputServed struct { - Height uint64 - ConfirmationDelay *big.Int - ProofG1X *big.Int - ProofG1Y *big.Int -} - -type VRFBeaconTypesVRFOutput struct { - BlockHeight uint64 - ConfirmationDelay *big.Int - VrfOutput ECCArithmeticG1Point - Callbacks []VRFBeaconTypesCostedCallback - ShouldStore bool -} - -var VRFBeaconMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"contractIVRFCoordinatorProducerAPI\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"contractDKG\",\"name\":\"keyProvider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"keyID\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualLength\",\"type\":\"uint256\"}],\"name\":\"CalldataLengthMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotAcceptPayeeship\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"providedHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"onchainHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"blockHeight\",\"type\":\"uint64\"}],\"name\":\"HistoryDomainSeparatorWrong\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numTransmitters\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numPayees\",\"type\":\"uint256\"}],\"name\":\"IncorrectNumberOfPayees\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"expectedNumSignatures\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"rsLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ssLength\",\"type\":\"uint256\"}],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requiredBalance\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"keyProvider\",\"type\":\"address\"}],\"name\":\"KeyInfoMustComeFromProvider\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeftGasExceedsInitialGas\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeOwnerOrBillingAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"numFaultyOracles\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"}],\"name\":\"NumberOfFaultyOraclesTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"expectedLength\",\"type\":\"uint256\"}],\"name\":\"OnchainConfigHasWrongLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCurrentPayee\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"existingPayee\",\"type\":\"address\"}],\"name\":\"PayeeAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"repeatedSignerAddress\",\"type\":\"address\"}],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"repeatedTransmitterAddress\",\"type\":\"address\"}],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportDoesNotContainNewOutputs\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numTransmitters\",\"type\":\"uint256\"}],\"name\":\"SignersTransmittersMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"maxOracles\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"providedOracles\",\"type\":\"uint256\"}],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"ocrVersion\",\"type\":\"uint64\"}],\"name\":\"UnknownConfigVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contractAccessControllerInterface\",\"name\":\"old\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contractAccessControllerInterface\",\"name\":\"current\",\"type\":\"address\"}],\"name\":\"BillingAccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maximumGasPrice\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"observationPayment\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"transmissionPayment\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"accountingGas\",\"type\":\"uint24\"}],\"name\":\"BillingSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint40\",\"name\":\"epochAndRound\",\"type\":\"uint40\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"juelsPerFeeCoin\",\"type\":\"uint192\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"NewTransmission\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contractLinkTokenInterface\",\"name\":\"linkToken\",\"type\":\"address\"}],\"name\":\"OraclePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"recentBlockHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"juelsPerFeeCoin\",\"type\":\"uint192\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"height\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint256\",\"name\":\"proofG1X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"proofG1Y\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structVRFBeaconTypes.OutputServed[]\",\"name\":\"outputsServed\",\"type\":\"tuple[]\"}],\"name\":\"OutputsServed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"current\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previous\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"current\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"requestIDs\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"successfulFulfillment\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes[]\",\"name\":\"truncatedErrorData\",\"type\":\"bytes[]\"},{\"indexed\":false,\"internalType\":\"uint96[]\",\"name\":\"subBalances\",\"type\":\"uint96[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"subIDs\",\"type\":\"uint256[]\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nextBeaconOutputHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAllowance\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"weiPerUnitLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"costJuels\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newSubBalance\",\"type\":\"uint256\"}],\"name\":\"RandomnessFulfillmentRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"}],\"name\":\"RandomnessRedeemed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nextBeaconOutputHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"costJuels\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newSubBalance\",\"type\":\"uint256\"}],\"name\":\"RandomnessRequested\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"NUM_CONF_DELAYS\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"p\",\"type\":\"uint256[2]\"}],\"internalType\":\"structECCArithmetic.G1Point\",\"name\":\"vrfOutput\",\"type\":\"tuple\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"gasAllowance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weiPerUnitLink\",\"type\":\"uint256\"}],\"internalType\":\"structVRFBeaconTypes.Callback\",\"name\":\"callback\",\"type\":\"tuple\"},{\"internalType\":\"uint96\",\"name\":\"price\",\"type\":\"uint96\"}],\"internalType\":\"structVRFBeaconTypes.CostedCallback[]\",\"name\":\"callbacks\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"shouldStore\",\"type\":\"bool\"}],\"internalType\":\"structVRFBeaconTypes.VRFOutput[]\",\"name\":\"outputs\",\"type\":\"tuple[]\"},{\"internalType\":\"uint192\",\"name\":\"juelsPerFeeCoin\",\"type\":\"uint192\"},{\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"recentBlockHeight\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"recentBlockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structVRFBeaconReport.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"exposeType\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBilling\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"maximumGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"observationPayment\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"transmissionPayment\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"accountingGas\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingAccessController\",\"outputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_coordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorProducerAPI\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_link\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashes\",\"type\":\"bytes32[]\"}],\"internalType\":\"structKeyDataStruct.KeyData\",\"name\":\"kd\",\"type\":\"tuple\"}],\"name\":\"keyGenerated\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"availableBalance\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"newKeyRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitterAddress\",\"type\":\"address\"}],\"name\":\"owedPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_keyID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_keyProvider\",\"outputs\":[{\"internalType\":\"contractDKG\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_provingKeyHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"maximumGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"observationPayment\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"transmissionPayment\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"accountingGas\",\"type\":\"uint24\"}],\"name\":\"setBilling\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"_billingAccessController\",\"type\":\"address\"}],\"name\":\"setBillingAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b5060405162004dfe38038062004dfe8339810160408190526200003491620001c7565b8181858581813380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000103565b5050506001600160a01b03918216608052811660a052600e80546001600160a01b03191695909116949094179093555060c05250620002219350505050565b336001600160a01b038216036200015d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620001c457600080fd5b50565b60008060008060808587031215620001de57600080fd5b8451620001eb81620001ae565b6020860151909450620001fe81620001ae565b60408601519093506200021181620001ae565b6060959095015193969295505050565b60805160a05160c051614b28620002d660003960006104810152600081816103820152818161114e015281816112260152818161131c0152818161141d015281816114bb01528181612216015281816122ee015281816124650152818161275a01528181612b8301528181612c5b0152818161316501526136cd01526000818161032b015281816112540152818161144a0152818161231c015281816124c301528181612c8901526130500152614b286000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c8063afcb95d7116100f9578063d09dc33911610097578063e53bbc9a11610071578063e53bbc9a146104c7578063eb5dcd6c146104da578063f2fde38b146104ed578063fbffd2c11461050057600080fd5b8063d09dc339146104a3578063d57fc45a146104ab578063e3d0e712146104b457600080fd5b8063bf2732c7116100d3578063bf2732c714610438578063c10753291461044b578063c4c92b371461045e578063cc31f7dd1461047c57600080fd5b8063afcb95d7146103e8578063b121e14714610412578063b1dc65a41461042557600080fd5b806379ba5097116101665780638a1b1772116101405780638a1b17721461037d5780638ac28d5a146103a45780638da5cb5b146103b75780639c849b30146103d557600080fd5b806379ba50971461031e5780637d253aff1461032657806381ff70481461034d57600080fd5b806329937268116101a257806329937268146102415780632f7527cc146102b757806355e48749146102d15780635f27026f146102d957600080fd5b806305aeed58146101c95780630eafb25b146101dc578063181f5a7714610202575b600080fd5b6101da6101d73660046137f7565b50565b005b6101ef6101ea366004613854565b610513565b6040519081526020015b60405180910390f35b604080518082018252600f81527f565246426561636f6e20312e302e300000000000000000000000000000000000602082015290516101f991906138df565b60025460035460408051610100840467ffffffffffffffff9081168252690100000000000000000085048116602083015271010000000000000000000000000000000000909404841691810191909152918116606083015268010000000000000000900462ffffff16608082015260a0016101f9565b6102bf600881565b60405160ff90911681526020016101f9565b6101da61059f565b600e546102f99073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f9565b6101da61061c565b6102f97f000000000000000000000000000000000000000000000000000000000000000081565b6004546005546040805163ffffffff808516825264010000000090940490931660208401528201526060016101f9565b6102f97f000000000000000000000000000000000000000000000000000000000000000081565b6101da6103b2366004613854565b610719565b60005473ffffffffffffffffffffffffffffffffffffffff166102f9565b6101da6103e336600461393e565b610782565b6005546006546040805160008152602081019390935263ffffffff909116908201526060016101f9565b6101da610420366004613854565b6109d4565b6101da6104333660046139ec565b610acc565b6101da610446366004613c89565b610f87565b6101da610459366004613d56565b611046565b600d5473ffffffffffffffffffffffffffffffffffffffff166102f9565b6101ef7f000000000000000000000000000000000000000000000000000000000000000081565b6101ef6113e0565b6101ef600f5481565b6101da6104c2366004613db9565b611573565b6101da6104d5366004613eb8565b611dc9565b6101da6104e8366004613f29565b61201b565b6101da6104fb366004613854565b612174565b6101da61050e366004613854565b612185565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602090815260408083208151606081018352905460ff80821615158084526101008304909116948301949094526201000090046bffffffffffffffffffffffff1691810191909152906105875750600092915050565b604001516bffffffffffffffffffffffff1692915050565b600e5473ffffffffffffffffffffffffffffffffffffffff16338114610614576040517f292f4fb500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b506000600f55565b60015473ffffffffffffffffffffffffffffffffffffffff16331461069d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161060b565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b73ffffffffffffffffffffffffffffffffffffffff8181166000908152600b6020526040902054163314610779576040517fdce38c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101d781612196565b61078a612569565b8281146107cd576040517f36d20459000000000000000000000000000000000000000000000000000000008152600481018490526024810182905260440161060b565b60005b838110156109cd5760008585838181106107ec576107ec613f62565b90506020020160208101906108019190613854565b9050600084848481811061081757610817613f62565b905060200201602081019061082c9190613854565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600b602052604090205491925016801580158161089257508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b156108e9576040517febdf175600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80861660048301528316602482015260440161060b565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152600b6020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016858316908117909155908316146109b6578273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b360405160405180910390a45b5050505080806109c590613fc0565b9150506107d0565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8181166000908152600c6020526040902054163314610a34576040517f9d12ec4f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600b602090815260408083208054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217909355600c909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b60005a6040805160c08101825260025460ff808216835267ffffffffffffffff61010083048116602080860191909152690100000000000000000084048216858701527101000000000000000000000000000000000090930481166060850152600354908116608085015262ffffff680100000000000000009091041660a08401523360009081526007835293909320549394509092908c01359116610ba0576040517fb1c1f68e00000000000000000000000000000000000000000000000000000000815233600482015260240161060b565b6005548b3514610bea576005546040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101919091528b35602482015260440161060b565b610bf88a8a8a8a8a8a6125ec565b8151610c05906001613ff8565b60ff1687141580610c165750868514155b15610c6e578151610c28906001613ff8565b6040517ffc33647500000000000000000000000000000000000000000000000000000000815260ff9091166004820152602481018890526044810186905260640161060b565b60008a8a604051610c80929190614011565b604051908190038120610c97918e90602001614021565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012083830190925260008084529083018190529092509060005b8a811015610e885760006001858a8460208110610d0457610d04613f62565b610d1191901a601b613ff8565b8f8f86818110610d2357610d23613f62565b905060200201358e8e87818110610d3c57610d3c613f62565b9050602002013560405160008152602001604052604051610d79949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610d9b573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526008602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955092509050610e61576040517f20fb74ee00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161060b565b826020015160080260ff166001901b84019350508080610e8090613fc0565b915050610ce5565b5081827e010101010101010101010101010101010101010101010101010101010101011614610ee3576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009150819050610f328d826020020135848e8e8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061267c92505050565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff600888901c161790559092509050610f7884838388336128c6565b50505050505050505050505050565b600e5473ffffffffffffffffffffffffffffffffffffffff16338114610ff7576040517f292f4fb500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161060b565b81516040516110099190602001614035565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120600f555050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906111075750600d546040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690636b14daf8906110c4903390600090369060040161409a565b602060405180830381865afa1580156110e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110591906140da565b155b1561113e576040517fc04ecc2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611148612a24565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663597d2f3c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111db91906140f5565b905060006111e9828461410e565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf91906140f5565b905081811015611305576040517fcf479181000000000000000000000000000000000000000000000000000000008152600481018290526024810183905260440161060b565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663f99b1d688761135561134f8686614121565b89612b1f565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b1580156113c057600080fd5b505af11580156113d4573d6000803e3d6000fd5b50505050505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b591906140f5565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663597d2f3c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611524573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154891906140f5565b90506000611554612a24565b9050816115618285614134565b61156b9190614134565b935050505090565b888787601f8311156115bb576040517f809fc428000000000000000000000000000000000000000000000000000000008152601f60048201526024810184905260440161060b565b8183146115fe576040517f988a0804000000000000000000000000000000000000000000000000000000008152600481018490526024810183905260440161060b565b61160981600361415b565b60ff168311611650576040517ffda9db7800000000000000000000000000000000000000000000000000000000815260ff821660048201526024810184905260440161060b565b61165c8160ff16612b39565b611664612569565b60006040518060c001604052808f8f80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505081526020018d8d8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050509082525060ff8c1660208083019190915260408051601f8d0183900483028101830182528c8152920191908c908c908190840183828082843760009201919091525050509082525067ffffffffffffffff891660208083019190915260408051601f8a01839004830281018301825289815292019190899089908190840183828082843760009201919091525050509152509050611786612b73565b60095460005b8181101561187f576000600982815481106117a9576117a9613f62565b6000918252602082200154600a805473ffffffffffffffffffffffffffffffffffffffff909216935090849081106117e3576117e3613f62565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff948516835260088252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905594168252600790529190912080547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000169055508061187781613fc0565b91505061178c565b5061188c6009600061373a565b611898600a600061373a565b60005b825151811015611c215760086000846000015183815181106118bf576118bf613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff161561196357825180518290811061190c5761190c613f62565b60200260200101516040517f7451f83e00000000000000000000000000000000000000000000000000000000815260040161060b919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b604080518082019091526001815260ff82166020820152835180516008916000918590811061199457611994613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281810192909252604001600090812083518154948401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169015157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010060ff90951694909402939093179092558401518051600792919084908110611a4657611a46613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611aec5782602001518181518110611a9557611a95613f62565b60200260200101516040517fe8d2989900000000000000000000000000000000000000000000000000000000815260040161060b919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180606001604052806001151581526020018260ff16815260200160006bffffffffffffffffffffffff168152506007600085602001518481518110611b3657611b36613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600020835181549385015194909201516bffffffffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff931515939093167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090941693909317919091179290921617905580611c1981613fc0565b91505061189b565b5081518051611c3891600991602090910190613758565b506020808301518051611c4f92600a920190613758565b506040820151600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600454640100000000900463ffffffff16611c9f6131d5565b6004805463ffffffff928316640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff82168117909255600092611ced9281169116176001614177565b905080600460006101000a81548163ffffffff021916908363ffffffff1602179055506000611d4146308463ffffffff16886000015189602001518a604001518b606001518c608001518d60a0015161326c565b9050806005819055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e058360055484886000015189602001518a604001518b606001518c608001518d60a00151604051611da3999897969594939291906141e5565b60405180910390a1611db58d8d613317565b505050505050505050505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611e8a5750600d546040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690636b14daf890611e47903390600090369060040161409a565b602060405180830381865afa158015611e64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8891906140da565b155b15611ec1576040517fc04ecc2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ec9612b73565b6002805467ffffffffffffffff8581167101000000000000000000000000000000000081027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff898416690100000000000000000081027fffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffff8d87166101008102919091167fffffffffffffffffffffffffffffff00000000000000000000000000000000ff909816979097171791909116919091179094556003805462ffffff87166801000000000000000081027fffffffffffffffffffffffffffffffffffffffffff00000000000000000000009092169489169485179190911790915560408051948552602085019590955293830152606082015260808101919091527f49275ddcdfc9c0519b3d094308c8bf675f06070a754ce90c152163cb6e66e8a09060a00160405180910390a15050505050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600b602052604090205416331461207b576040517fdce38c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811633036120ca576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600c6020526040902080548383167fffffffffffffffffffffffff00000000000000000000000000000000000000008216811790925590911690811461216f5760405173ffffffffffffffffffffffffffffffffffffffff8084169133918616907f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836790600090a45b505050565b61217c612569565b6101d781613325565b61218d612569565b6101d78161341a565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600760209081526040918290208251606081018452905460ff80821615158084526101008304909116938301939093526201000090046bffffffffffffffffffffffff1692810192909252612205575050565b600061221083610513565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663597d2f3c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a391906140f5565b905060006122b1828461410e565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238791906140f5565b9050818110156123cd576040517fcf479181000000000000000000000000000000000000000000000000000000008152600481018290526024810183905260440161060b565b83156125615773ffffffffffffffffffffffffffffffffffffffff8681166000908152600b602090815260408083205460079092529182902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff16905590517ff99b1d680000000000000000000000000000000000000000000000000000000081529082166004820181905260248201879052917f0000000000000000000000000000000000000000000000000000000000000000169063f99b1d6890604401600060405180830381600087803b1580156124a957600080fd5b505af11580156124bd573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c8860405161255791815260200190565b60405180910390a4505b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146125ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161060b565b565b60006125f982602061427b565b61260485602061427b565b6126108861014461410e565b61261a919061410e565b612624919061410e565b61262f90600061410e565b9050368114612673576040517ff7b94f0a0000000000000000000000000000000000000000000000000000000081526004810182905236602482015260440161060b565b50505050505050565b60008060008380602001905181019061269591906144bf565b905060006126a682606001516134c2565b90508082608001511461270957608082015160608301516040517faed0afe500000000000000000000000000000000000000000000000000000000815260048101929092526024820183905267ffffffffffffffff16604482015260640161060b565b81516020830151604080850151606086015191517f76f2e3f400000000000000000000000000000000000000000000000000000000815260009473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016946376f2e3f4946127929492939192916004016147fa565b6020604051808303816000875af11580156127b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d591906140da565b90508061280e576040517f69c920fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8664ffffffffff167ffc3c7a7927e878a0fca37c904953c3c75cee3ca1d1640184a0ab1c65eec6274333856020015186604001518c6040516128a5949392919073ffffffffffffffffffffffffffffffffffffffff94909416845277ffffffffffffffffffffffffffffffffffffffffffffffff92909216602084015267ffffffffffffffff166040830152606082015260800190565b60405180910390a28260200151836040015194509450505050935093915050565b60006128f23a67ffffffffffffffff8616156128e257856128e8565b87604001515b88602001516135a5565b90506010360260005a9050600061291b8663ffffffff1685858c60a0015162ffffff16866135f6565b90506000670de0b6b3a764000077ffffffffffffffffffffffffffffffffffffffffffffffff8a16830273ffffffffffffffffffffffffffffffffffffffff881660009081526007602052604090205460808d01519290910492506201000090046bffffffffffffffffffffffff9081169167ffffffffffffffff16828401019081168211156129b157505050505050506109cd565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260076020526040902080546bffffffffffffffffffffffff90921662010000027fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff9092169190911790555050505050505050505050565b600080600a805480602002602001604051908101604052809291908181526020018280548015612a8a57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612a5f575b505083519394506000925050505b81811015612b195760076000848381518110612ab657612ab6613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054612b05906201000090046bffffffffffffffffffffffff168561410e565b935080612b1181613fc0565b915050612a98565b50505090565b600081831015612b30575081612b33565b50805b92915050565b806000036101d7576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b7d612a24565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663597d2f3c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1091906140f5565b90506000612c1e828461410e565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf491906140f5565b905081811015612d3a576040517fcf479181000000000000000000000000000000000000000000000000000000008152600481018290526024810183905260440161060b565b6000600a805480602002602001604051908101604052809291908181526020018280548015612d9f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612d74575b5050505050905060008151905060008167ffffffffffffffff811115612dc757612dc7613aa3565b604051908082528060200260200182016040528015612df0578160200160208202803683370190505b50905060008267ffffffffffffffff811115612e0e57612e0e613aa3565b604051908082528060200260200182016040528015612e37578160200160208202803683370190505b5090506000805b8481101561311157600060076000888481518110612e5e57612e5e613f62565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160029054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff169050600060076000898581518110612ee457612ee4613f62565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080546bffffffffffffffffffffffff9290921662010000027fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff909216919091179055808015613107576000600b60008a8681518110612f7557612f75613f62565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905080878681518110612fed57612fed613f62565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508186868151811061303a5761303a613f62565b60200260200101818152505084806001019550507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff168a86815181106130ae576130ae613f62565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c856040516130fd91815260200190565b60405180910390a4505b5050600101612e3e565b5081518114613121578082528083525b8151156131ca576040517f73433a2f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906373433a2f9061319c908690869060040161496a565b600060405180830381600087803b1580156131b657600080fd5b505af1158015610f78573d6000803e3d6000fd5b505050505050505050565b60004661a4b18114806131ea575062066eed81145b1561326557606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561323b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061325f91906140f5565b91505090565b4391505090565b6000808a8a8a8a8a8a8a8a8a604051602001613290999897969594939291906149c1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b613321828261363e565b5050565b3373ffffffffffffffffffffffffffffffffffffffff8216036133a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161060b565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600d5473ffffffffffffffffffffffffffffffffffffffff908116908216811461332157600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560408051928416835260208301919091527f793cb73064f3c8cde7e187ae515511e6e56d1ee89bf08b82fa60fb70f8d48912910160405180910390a15050565b60004661a4b18114806134d7575062066eed81145b15613595576101008367ffffffffffffffff166134f26131d5565b6134fc9190614121565b111561350b5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a8290602401602060405180830381865afa15801561356a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358e91906140f5565b9392505050565b505067ffffffffffffffff164090565b60008367ffffffffffffffff84168110156135d9576002858567ffffffffffffffff1603816135d6576135d661493b565b04015b6135ed818467ffffffffffffffff16612b1f565b95945050505050565b600081861015613632576040517f3fef97df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50909303019091010290565b610100818114613680578282826040517f418a179b00000000000000000000000000000000000000000000000000000000815260040161060b93929190614a56565b600061368e83850185614a7a565b90506040517f8eef585f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690638eef585f90613702908490600401614ae4565b600060405180830381600087803b15801561371c57600080fd5b505af1158015613730573d6000803e3d6000fd5b5050505050505050565b50805460008255906000526020600020908101906101d791906137e2565b8280548282559060005260206000209081019282156137d2579160200282015b828111156137d257825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613778565b506137de9291506137e2565b5090565b5b808211156137de57600081556001016137e3565b60006020828403121561380957600080fd5b813567ffffffffffffffff81111561382057600080fd5b820160a0818503121561358e57600080fd5b73ffffffffffffffffffffffffffffffffffffffff811681146101d757600080fd5b60006020828403121561386657600080fd5b813561358e81613832565b60005b8381101561388c578181015183820152602001613874565b50506000910152565b600081518084526138ad816020860160208601613871565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061358e6020830184613895565b60008083601f84011261390457600080fd5b50813567ffffffffffffffff81111561391c57600080fd5b6020830191508360208260051b850101111561393757600080fd5b9250929050565b6000806000806040858703121561395457600080fd5b843567ffffffffffffffff8082111561396c57600080fd5b613978888389016138f2565b9096509450602087013591508082111561399157600080fd5b5061399e878288016138f2565b95989497509550505050565b60008083601f8401126139bc57600080fd5b50813567ffffffffffffffff8111156139d457600080fd5b60208301915083602082850101111561393757600080fd5b60008060008060008060008060e0898b031215613a0857600080fd5b606089018a811115613a1957600080fd5b8998503567ffffffffffffffff80821115613a3357600080fd5b613a3f8c838d016139aa565b909950975060808b0135915080821115613a5857600080fd5b613a648c838d016138f2565b909750955060a08b0135915080821115613a7d57600080fd5b50613a8a8b828c016138f2565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613af557613af5613aa3565b60405290565b604051610100810167ffffffffffffffff81118282101715613af557613af5613aa3565b60405160a0810167ffffffffffffffff81118282101715613af557613af5613aa3565b6040516020810167ffffffffffffffff81118282101715613af557613af5613aa3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613bac57613bac613aa3565b604052919050565b600067ffffffffffffffff821115613bce57613bce613aa3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600067ffffffffffffffff821115613c1457613c14613aa3565b5060051b60200190565b600082601f830112613c2f57600080fd5b81356020613c44613c3f83613bfa565b613b65565b82815260059290921b84018101918181019086841115613c6357600080fd5b8286015b84811015613c7e5780358352918301918301613c67565b509695505050505050565b60006020808385031215613c9c57600080fd5b823567ffffffffffffffff80821115613cb457600080fd5b9084019060408287031215613cc857600080fd5b613cd0613ad2565b823582811115613cdf57600080fd5b8301601f81018813613cf057600080fd5b8035613cfe613c3f82613bb4565b8181528987838501011115613d1257600080fd5b818784018883013760008783830101528084525050508383013582811115613d3957600080fd5b613d4588828601613c1e565b948201949094529695505050505050565b60008060408385031215613d6957600080fd5b8235613d7481613832565b946020939093013593505050565b803560ff81168114613d9357600080fd5b919050565b67ffffffffffffffff811681146101d757600080fd5b8035613d9381613d98565b60008060008060008060008060008060c08b8d031215613dd857600080fd5b8a3567ffffffffffffffff80821115613df057600080fd5b613dfc8e838f016138f2565b909c509a5060208d0135915080821115613e1557600080fd5b613e218e838f016138f2565b909a509850889150613e3560408e01613d82565b975060608d0135915080821115613e4b57600080fd5b613e578e838f016139aa565b9097509550859150613e6b60808e01613dae565b945060a08d0135915080821115613e8157600080fd5b50613e8e8d828e016139aa565b915080935050809150509295989b9194979a5092959850565b62ffffff811681146101d757600080fd5b600080600080600060a08688031215613ed057600080fd5b8535613edb81613d98565b94506020860135613eeb81613d98565b93506040860135613efb81613d98565b92506060860135613f0b81613d98565b91506080860135613f1b81613ea7565b809150509295509295909350565b60008060408385031215613f3c57600080fd5b8235613f4781613832565b91506020830135613f5781613832565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ff157613ff1613f91565b5060010190565b60ff8181168382160190811115612b3357612b33613f91565b8183823760009101908152919050565b828152606082602083013760800192915050565b60008251614047818460208701613871565b9190910192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082015260006135ed604083018486614051565b80518015158114613d9357600080fd5b6000602082840312156140ec57600080fd5b61358e826140ca565b60006020828403121561410757600080fd5b5051919050565b80820180821115612b3357612b33613f91565b81810381811115612b3357612b33613f91565b818103600083128015838313168383128216171561415457614154613f91565b5092915050565b60ff818116838216029081169081811461415457614154613f91565b63ffffffff81811683821601908082111561415457614154613f91565b600081518084526020808501945080840160005b838110156141da57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016141a8565b509495945050505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526142158184018a614194565b905082810360808401526142298189614194565b905060ff871660a084015282810360c08401526142468187613895565b905067ffffffffffffffff851660e084015282810361010084015261426b8185613895565b9c9b505050505050505050505050565b8082028115828204841417612b3357612b33613f91565b8051613d9381613d98565b805161ffff81168114613d9357600080fd5b8051613d9381613832565b600082601f8301126142cb57600080fd5b81516142d9613c3f82613bb4565b8181528460208386010111156142ee57600080fd5b6142ff826020830160208701613871565b949350505050565b80516bffffffffffffffffffffffff81168114613d9357600080fd5b600082601f83011261433457600080fd5b81516020614344613c3f83613bfa565b82815260059290921b8401810191818101908684111561436357600080fd5b8286015b84811015613c7e57805167ffffffffffffffff8082111561438757600080fd5b908801907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06040838c03820112156143be57600080fd5b6143c6613ad2565b87840151838111156143d757600080fd5b8401610100818e03840112156143ec57600080fd5b6143f4613afb565b92508881015183526144086040820161429d565b89840152614418606082016142af565b604084015260808101518481111561442f57600080fd5b61443d8e8b838501016142ba565b60608501525061444f60a08201614307565b608084015260c081015160a084015260e081015160c084015261010081015160e08401525081815261448360408501614307565b818901528652505050918301918301614367565b805177ffffffffffffffffffffffffffffffffffffffffffffffff81168114613d9357600080fd5b6000602082840312156144d157600080fd5b815167ffffffffffffffff808211156144e957600080fd5b9083019060a082860312156144fd57600080fd5b614505613b1f565b82518281111561451457600080fd5b8301601f8101871361452557600080fd5b8051614533613c3f82613bfa565b8082825260208201915060208360051b85010192508983111561455557600080fd5b602084015b838110156146a25780518781111561457157600080fd5b850160c0818d037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156145a557600080fd5b6145ad613b1f565b60208201516145bb81613d98565b815260408201516145cb81613ea7565b60208201526040828e037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa001121561460257600080fd5b61460a613b42565b8d607f84011261461957600080fd5b614621613ad2565b808f60a08601111561463257600080fd5b606085015b60a08601811015614652578051835260209283019201614637565b50825250604082015260a08201518981111561466d57600080fd5b61467c8e602083860101614323565b60608301525061468e60c083016140ca565b60808201528452506020928301920161455a565b508452506146b591505060208401614497565b60208201526146c660408401614292565b60408201526146d760608401614292565b60608201526080830151608082015280935050505092915050565b600081518084526020808501808196508360051b8101915082860160005b858110156147ed57828403895281516040815181875280518288015287810151606061ffff8216818a01528383015193506080915073ffffffffffffffffffffffffffffffffffffffff8416828a01528083015193505061010060a081818b015261477f6101408b0186613895565b9284015192945060c06147a18b8201856bffffffffffffffffffffffff169052565b9084015160e08b81019190915290840151918a01919091529091015161012088015250908601516bffffffffffffffffffffffff16948601949094529784019790840190600101614710565b5091979650505050505050565b6000608080830181845280885180835260a092508286019150828160051b8701016020808c016000805b858110156148df578a85037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600187528251805167ffffffffffffffff1686528481015162ffffff16858701526040808201515160c091859089015b600282101561489e57825181529188019160019190910190880161487f565b5050506060820151818c8901526148b7828901826146f2565b928c0151801515898d01529291506148cc9050565b9785019795505091830191600101614824565b50505081965061490a8189018c77ffffffffffffffffffffffffffffffffffffffffffffffff169052565b505050505050614926604083018567ffffffffffffffff169052565b67ffffffffffffffff831660608301526135ed565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60408152600061497d6040830185614194565b82810360208481019190915284518083528582019282019060005b818110156149b457845183529383019391830191600101614998565b5090979650505050505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614a088285018b614194565b91508382036080850152614a1c828a614194565b915060ff881660a085015283820360c0850152614a398288613895565b90861660e0850152838103610100850152905061426b8185613895565b604081526000614a6a604083018587614051565b9050826020830152949350505050565b6000610100808385031215614a8e57600080fd5b83601f840112614a9d57600080fd5b614aa5613afb565b908301908085831115614ab757600080fd5b845b83811015614ada578035614acc81613ea7565b835260209283019201614ab9565b5095945050505050565b6101008101818360005b6008811015614b1257815162ffffff16835260209283019290910190600101614aee565b5050509291505056fea164736f6c6343000813000a", -} - -var VRFBeaconABI = VRFBeaconMetaData.ABI - -var VRFBeaconBin = VRFBeaconMetaData.Bin - -func DeployVRFBeacon(auth *bind.TransactOpts, backend bind.ContractBackend, link common.Address, coordinator common.Address, keyProvider common.Address, keyID [32]byte) (common.Address, *types.Transaction, *VRFBeacon, error) { - parsed, err := VRFBeaconMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFBeaconBin), backend, link, coordinator, keyProvider, keyID) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &VRFBeacon{VRFBeaconCaller: VRFBeaconCaller{contract: contract}, VRFBeaconTransactor: VRFBeaconTransactor{contract: contract}, VRFBeaconFilterer: VRFBeaconFilterer{contract: contract}}, nil -} - -type VRFBeacon struct { - address common.Address - abi abi.ABI - VRFBeaconCaller - VRFBeaconTransactor - VRFBeaconFilterer -} - -type VRFBeaconCaller struct { - contract *bind.BoundContract -} - -type VRFBeaconTransactor struct { - contract *bind.BoundContract -} - -type VRFBeaconFilterer struct { - contract *bind.BoundContract -} - -type VRFBeaconSession struct { - Contract *VRFBeacon - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type VRFBeaconCallerSession struct { - Contract *VRFBeaconCaller - CallOpts bind.CallOpts -} - -type VRFBeaconTransactorSession struct { - Contract *VRFBeaconTransactor - TransactOpts bind.TransactOpts -} - -type VRFBeaconRaw struct { - Contract *VRFBeacon -} - -type VRFBeaconCallerRaw struct { - Contract *VRFBeaconCaller -} - -type VRFBeaconTransactorRaw struct { - Contract *VRFBeaconTransactor -} - -func NewVRFBeacon(address common.Address, backend bind.ContractBackend) (*VRFBeacon, error) { - abi, err := abi.JSON(strings.NewReader(VRFBeaconABI)) - if err != nil { - return nil, err - } - contract, err := bindVRFBeacon(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &VRFBeacon{address: address, abi: abi, VRFBeaconCaller: VRFBeaconCaller{contract: contract}, VRFBeaconTransactor: VRFBeaconTransactor{contract: contract}, VRFBeaconFilterer: VRFBeaconFilterer{contract: contract}}, nil -} - -func NewVRFBeaconCaller(address common.Address, caller bind.ContractCaller) (*VRFBeaconCaller, error) { - contract, err := bindVRFBeacon(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &VRFBeaconCaller{contract: contract}, nil -} - -func NewVRFBeaconTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFBeaconTransactor, error) { - contract, err := bindVRFBeacon(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &VRFBeaconTransactor{contract: contract}, nil -} - -func NewVRFBeaconFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFBeaconFilterer, error) { - contract, err := bindVRFBeacon(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &VRFBeaconFilterer{contract: contract}, nil -} - -func bindVRFBeacon(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := VRFBeaconMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_VRFBeacon *VRFBeaconRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFBeacon.Contract.VRFBeaconCaller.contract.Call(opts, result, method, params...) -} - -func (_VRFBeacon *VRFBeaconRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFBeacon.Contract.VRFBeaconTransactor.contract.Transfer(opts) -} - -func (_VRFBeacon *VRFBeaconRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFBeacon.Contract.VRFBeaconTransactor.contract.Transact(opts, method, params...) -} - -func (_VRFBeacon *VRFBeaconCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFBeacon.Contract.contract.Call(opts, result, method, params...) -} - -func (_VRFBeacon *VRFBeaconTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFBeacon.Contract.contract.Transfer(opts) -} - -func (_VRFBeacon *VRFBeaconTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFBeacon.Contract.contract.Transact(opts, method, params...) -} - -func (_VRFBeacon *VRFBeaconCaller) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "NUM_CONF_DELAYS") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) NUMCONFDELAYS() (uint8, error) { - return _VRFBeacon.Contract.NUMCONFDELAYS(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) NUMCONFDELAYS() (uint8, error) { - return _VRFBeacon.Contract.NUMCONFDELAYS(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) GetBilling(opts *bind.CallOpts) (GetBilling, - - error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "getBilling") - - outstruct := new(GetBilling) - if err != nil { - return *outstruct, err - } - - outstruct.MaximumGasPrice = *abi.ConvertType(out[0], new(uint64)).(*uint64) - outstruct.ReasonableGasPrice = *abi.ConvertType(out[1], new(uint64)).(*uint64) - outstruct.ObservationPayment = *abi.ConvertType(out[2], new(uint64)).(*uint64) - outstruct.TransmissionPayment = *abi.ConvertType(out[3], new(uint64)).(*uint64) - outstruct.AccountingGas = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -func (_VRFBeacon *VRFBeaconSession) GetBilling() (GetBilling, - - error) { - return _VRFBeacon.Contract.GetBilling(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) GetBilling() (GetBilling, - - error) { - return _VRFBeacon.Contract.GetBilling(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) GetBillingAccessController(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "getBillingAccessController") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) GetBillingAccessController() (common.Address, error) { - return _VRFBeacon.Contract.GetBillingAccessController(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) GetBillingAccessController() (common.Address, error) { - return _VRFBeacon.Contract.GetBillingAccessController(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) ICoordinator(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "i_coordinator") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) ICoordinator() (common.Address, error) { - return _VRFBeacon.Contract.ICoordinator(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) ICoordinator() (common.Address, error) { - return _VRFBeacon.Contract.ICoordinator(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) ILink(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "i_link") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) ILink() (common.Address, error) { - return _VRFBeacon.Contract.ILink(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) ILink() (common.Address, error) { - return _VRFBeacon.Contract.ILink(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, - - error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "latestConfigDetails") - - outstruct := new(LatestConfigDetails) - if err != nil { - return *outstruct, err - } - - outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) - outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) - - return *outstruct, err - -} - -func (_VRFBeacon *VRFBeaconSession) LatestConfigDetails() (LatestConfigDetails, - - error) { - return _VRFBeacon.Contract.LatestConfigDetails(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) LatestConfigDetails() (LatestConfigDetails, - - error) { - return _VRFBeacon.Contract.LatestConfigDetails(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, - - error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "latestConfigDigestAndEpoch") - - outstruct := new(LatestConfigDigestAndEpoch) - if err != nil { - return *outstruct, err - } - - outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) - - return *outstruct, err - -} - -func (_VRFBeacon *VRFBeaconSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, - - error) { - return _VRFBeacon.Contract.LatestConfigDigestAndEpoch(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, - - error) { - return _VRFBeacon.Contract.LatestConfigDigestAndEpoch(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "linkAvailableForPayment") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) LinkAvailableForPayment() (*big.Int, error) { - return _VRFBeacon.Contract.LinkAvailableForPayment(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) LinkAvailableForPayment() (*big.Int, error) { - return _VRFBeacon.Contract.LinkAvailableForPayment(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) OwedPayment(opts *bind.CallOpts, transmitterAddress common.Address) (*big.Int, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "owedPayment", transmitterAddress) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) OwedPayment(transmitterAddress common.Address) (*big.Int, error) { - return _VRFBeacon.Contract.OwedPayment(&_VRFBeacon.CallOpts, transmitterAddress) -} - -func (_VRFBeacon *VRFBeaconCallerSession) OwedPayment(transmitterAddress common.Address) (*big.Int, error) { - return _VRFBeacon.Contract.OwedPayment(&_VRFBeacon.CallOpts, transmitterAddress) -} - -func (_VRFBeacon *VRFBeaconCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) Owner() (common.Address, error) { - return _VRFBeacon.Contract.Owner(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) Owner() (common.Address, error) { - return _VRFBeacon.Contract.Owner(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) SKeyID(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "s_keyID") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) SKeyID() ([32]byte, error) { - return _VRFBeacon.Contract.SKeyID(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) SKeyID() ([32]byte, error) { - return _VRFBeacon.Contract.SKeyID(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) SKeyProvider(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "s_keyProvider") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) SKeyProvider() (common.Address, error) { - return _VRFBeacon.Contract.SKeyProvider(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) SKeyProvider() (common.Address, error) { - return _VRFBeacon.Contract.SKeyProvider(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "s_provingKeyHash") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) SProvingKeyHash() ([32]byte, error) { - return _VRFBeacon.Contract.SProvingKeyHash(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) SProvingKeyHash() ([32]byte, error) { - return _VRFBeacon.Contract.SProvingKeyHash(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _VRFBeacon.contract.Call(opts, &out, "typeAndVersion") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -func (_VRFBeacon *VRFBeaconSession) TypeAndVersion() (string, error) { - return _VRFBeacon.Contract.TypeAndVersion(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconCallerSession) TypeAndVersion() (string, error) { - return _VRFBeacon.Contract.TypeAndVersion(&_VRFBeacon.CallOpts) -} - -func (_VRFBeacon *VRFBeaconTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "acceptOwnership") -} - -func (_VRFBeacon *VRFBeaconSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFBeacon.Contract.AcceptOwnership(&_VRFBeacon.TransactOpts) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFBeacon.Contract.AcceptOwnership(&_VRFBeacon.TransactOpts) -} - -func (_VRFBeacon *VRFBeaconTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "acceptPayeeship", transmitter) -} - -func (_VRFBeacon *VRFBeaconSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.AcceptPayeeship(&_VRFBeacon.TransactOpts, transmitter) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.AcceptPayeeship(&_VRFBeacon.TransactOpts, transmitter) -} - -func (_VRFBeacon *VRFBeaconTransactor) ExposeType(opts *bind.TransactOpts, arg0 VRFBeaconReportReport) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "exposeType", arg0) -} - -func (_VRFBeacon *VRFBeaconSession) ExposeType(arg0 VRFBeaconReportReport) (*types.Transaction, error) { - return _VRFBeacon.Contract.ExposeType(&_VRFBeacon.TransactOpts, arg0) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) ExposeType(arg0 VRFBeaconReportReport) (*types.Transaction, error) { - return _VRFBeacon.Contract.ExposeType(&_VRFBeacon.TransactOpts, arg0) -} - -func (_VRFBeacon *VRFBeaconTransactor) KeyGenerated(opts *bind.TransactOpts, kd KeyDataStructKeyData) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "keyGenerated", kd) -} - -func (_VRFBeacon *VRFBeaconSession) KeyGenerated(kd KeyDataStructKeyData) (*types.Transaction, error) { - return _VRFBeacon.Contract.KeyGenerated(&_VRFBeacon.TransactOpts, kd) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) KeyGenerated(kd KeyDataStructKeyData) (*types.Transaction, error) { - return _VRFBeacon.Contract.KeyGenerated(&_VRFBeacon.TransactOpts, kd) -} - -func (_VRFBeacon *VRFBeaconTransactor) NewKeyRequested(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "newKeyRequested") -} - -func (_VRFBeacon *VRFBeaconSession) NewKeyRequested() (*types.Transaction, error) { - return _VRFBeacon.Contract.NewKeyRequested(&_VRFBeacon.TransactOpts) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) NewKeyRequested() (*types.Transaction, error) { - return _VRFBeacon.Contract.NewKeyRequested(&_VRFBeacon.TransactOpts) -} - -func (_VRFBeacon *VRFBeaconTransactor) SetBilling(opts *bind.TransactOpts, maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "setBilling", maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) -} - -func (_VRFBeacon *VRFBeaconSession) SetBilling(maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetBilling(&_VRFBeacon.TransactOpts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) SetBilling(maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetBilling(&_VRFBeacon.TransactOpts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) -} - -func (_VRFBeacon *VRFBeaconTransactor) SetBillingAccessController(opts *bind.TransactOpts, _billingAccessController common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "setBillingAccessController", _billingAccessController) -} - -func (_VRFBeacon *VRFBeaconSession) SetBillingAccessController(_billingAccessController common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetBillingAccessController(&_VRFBeacon.TransactOpts, _billingAccessController) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) SetBillingAccessController(_billingAccessController common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetBillingAccessController(&_VRFBeacon.TransactOpts, _billingAccessController) -} - -func (_VRFBeacon *VRFBeaconTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) -} - -func (_VRFBeacon *VRFBeaconSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetConfig(&_VRFBeacon.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetConfig(&_VRFBeacon.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) -} - -func (_VRFBeacon *VRFBeaconTransactor) SetPayees(opts *bind.TransactOpts, transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "setPayees", transmitters, payees) -} - -func (_VRFBeacon *VRFBeaconSession) SetPayees(transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetPayees(&_VRFBeacon.TransactOpts, transmitters, payees) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) SetPayees(transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.SetPayees(&_VRFBeacon.TransactOpts, transmitters, payees) -} - -func (_VRFBeacon *VRFBeaconTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "transferOwnership", to) -} - -func (_VRFBeacon *VRFBeaconSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.TransferOwnership(&_VRFBeacon.TransactOpts, to) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.TransferOwnership(&_VRFBeacon.TransactOpts, to) -} - -func (_VRFBeacon *VRFBeaconTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "transferPayeeship", transmitter, proposed) -} - -func (_VRFBeacon *VRFBeaconSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.TransferPayeeship(&_VRFBeacon.TransactOpts, transmitter, proposed) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.TransferPayeeship(&_VRFBeacon.TransactOpts, transmitter, proposed) -} - -func (_VRFBeacon *VRFBeaconTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs) -} - -func (_VRFBeacon *VRFBeaconSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _VRFBeacon.Contract.Transmit(&_VRFBeacon.TransactOpts, reportContext, report, rs, ss, rawVs) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - return _VRFBeacon.Contract.Transmit(&_VRFBeacon.TransactOpts, reportContext, report, rs, ss, rawVs) -} - -func (_VRFBeacon *VRFBeaconTransactor) WithdrawFunds(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "withdrawFunds", recipient, amount) -} - -func (_VRFBeacon *VRFBeaconSession) WithdrawFunds(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFBeacon.Contract.WithdrawFunds(&_VRFBeacon.TransactOpts, recipient, amount) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) WithdrawFunds(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFBeacon.Contract.WithdrawFunds(&_VRFBeacon.TransactOpts, recipient, amount) -} - -func (_VRFBeacon *VRFBeaconTransactor) WithdrawPayment(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.contract.Transact(opts, "withdrawPayment", transmitter) -} - -func (_VRFBeacon *VRFBeaconSession) WithdrawPayment(transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.WithdrawPayment(&_VRFBeacon.TransactOpts, transmitter) -} - -func (_VRFBeacon *VRFBeaconTransactorSession) WithdrawPayment(transmitter common.Address) (*types.Transaction, error) { - return _VRFBeacon.Contract.WithdrawPayment(&_VRFBeacon.TransactOpts, transmitter) -} - -type VRFBeaconBillingAccessControllerSetIterator struct { - Event *VRFBeaconBillingAccessControllerSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconBillingAccessControllerSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconBillingAccessControllerSet) - 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(VRFBeaconBillingAccessControllerSet) - 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 *VRFBeaconBillingAccessControllerSetIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconBillingAccessControllerSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconBillingAccessControllerSet struct { - Old common.Address - Current common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterBillingAccessControllerSet(opts *bind.FilterOpts) (*VRFBeaconBillingAccessControllerSetIterator, error) { - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "BillingAccessControllerSet") - if err != nil { - return nil, err - } - return &VRFBeaconBillingAccessControllerSetIterator{contract: _VRFBeacon.contract, event: "BillingAccessControllerSet", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchBillingAccessControllerSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconBillingAccessControllerSet) (event.Subscription, error) { - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "BillingAccessControllerSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconBillingAccessControllerSet) - if err := _VRFBeacon.contract.UnpackLog(event, "BillingAccessControllerSet", 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 (_VRFBeacon *VRFBeaconFilterer) ParseBillingAccessControllerSet(log types.Log) (*VRFBeaconBillingAccessControllerSet, error) { - event := new(VRFBeaconBillingAccessControllerSet) - if err := _VRFBeacon.contract.UnpackLog(event, "BillingAccessControllerSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconBillingSetIterator struct { - Event *VRFBeaconBillingSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconBillingSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconBillingSet) - 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(VRFBeaconBillingSet) - 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 *VRFBeaconBillingSetIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconBillingSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconBillingSet struct { - MaximumGasPrice uint64 - ReasonableGasPrice uint64 - ObservationPayment uint64 - TransmissionPayment uint64 - AccountingGas *big.Int - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterBillingSet(opts *bind.FilterOpts) (*VRFBeaconBillingSetIterator, error) { - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "BillingSet") - if err != nil { - return nil, err - } - return &VRFBeaconBillingSetIterator{contract: _VRFBeacon.contract, event: "BillingSet", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchBillingSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconBillingSet) (event.Subscription, error) { - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "BillingSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconBillingSet) - if err := _VRFBeacon.contract.UnpackLog(event, "BillingSet", 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 (_VRFBeacon *VRFBeaconFilterer) ParseBillingSet(log types.Log) (*VRFBeaconBillingSet, error) { - event := new(VRFBeaconBillingSet) - if err := _VRFBeacon.contract.UnpackLog(event, "BillingSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconConfigSetIterator struct { - Event *VRFBeaconConfigSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconConfigSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconConfigSet) - 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(VRFBeaconConfigSet) - 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 *VRFBeaconConfigSetIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconConfigSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconConfigSet struct { - PreviousConfigBlockNumber uint32 - ConfigDigest [32]byte - ConfigCount uint64 - Signers []common.Address - Transmitters []common.Address - F uint8 - OnchainConfig []byte - OffchainConfigVersion uint64 - OffchainConfig []byte - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterConfigSet(opts *bind.FilterOpts) (*VRFBeaconConfigSetIterator, error) { - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "ConfigSet") - if err != nil { - return nil, err - } - return &VRFBeaconConfigSetIterator{contract: _VRFBeacon.contract, event: "ConfigSet", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconConfigSet) (event.Subscription, error) { - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "ConfigSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconConfigSet) - if err := _VRFBeacon.contract.UnpackLog(event, "ConfigSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParseConfigSet(log types.Log) (*VRFBeaconConfigSet, error) { - event := new(VRFBeaconConfigSet) - if err := _VRFBeacon.contract.UnpackLog(event, "ConfigSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconNewTransmissionIterator struct { - Event *VRFBeaconNewTransmission - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconNewTransmissionIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconNewTransmission) - 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(VRFBeaconNewTransmission) - 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 *VRFBeaconNewTransmissionIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconNewTransmissionIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconNewTransmission struct { - EpochAndRound *big.Int - Transmitter common.Address - JuelsPerFeeCoin *big.Int - ReasonableGasPrice uint64 - ConfigDigest [32]byte - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterNewTransmission(opts *bind.FilterOpts, epochAndRound []*big.Int) (*VRFBeaconNewTransmissionIterator, error) { - - var epochAndRoundRule []interface{} - for _, epochAndRoundItem := range epochAndRound { - epochAndRoundRule = append(epochAndRoundRule, epochAndRoundItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "NewTransmission", epochAndRoundRule) - if err != nil { - return nil, err - } - return &VRFBeaconNewTransmissionIterator{contract: _VRFBeacon.contract, event: "NewTransmission", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchNewTransmission(opts *bind.WatchOpts, sink chan<- *VRFBeaconNewTransmission, epochAndRound []*big.Int) (event.Subscription, error) { - - var epochAndRoundRule []interface{} - for _, epochAndRoundItem := range epochAndRound { - epochAndRoundRule = append(epochAndRoundRule, epochAndRoundItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "NewTransmission", epochAndRoundRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconNewTransmission) - if err := _VRFBeacon.contract.UnpackLog(event, "NewTransmission", 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 (_VRFBeacon *VRFBeaconFilterer) ParseNewTransmission(log types.Log) (*VRFBeaconNewTransmission, error) { - event := new(VRFBeaconNewTransmission) - if err := _VRFBeacon.contract.UnpackLog(event, "NewTransmission", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconOraclePaidIterator struct { - Event *VRFBeaconOraclePaid - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconOraclePaidIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconOraclePaid) - 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(VRFBeaconOraclePaid) - 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 *VRFBeaconOraclePaidIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconOraclePaidIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconOraclePaid struct { - Transmitter common.Address - Payee common.Address - Amount *big.Int - LinkToken common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterOraclePaid(opts *bind.FilterOpts, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (*VRFBeaconOraclePaidIterator, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var payeeRule []interface{} - for _, payeeItem := range payee { - payeeRule = append(payeeRule, payeeItem) - } - - var linkTokenRule []interface{} - for _, linkTokenItem := range linkToken { - linkTokenRule = append(linkTokenRule, linkTokenItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "OraclePaid", transmitterRule, payeeRule, linkTokenRule) - if err != nil { - return nil, err - } - return &VRFBeaconOraclePaidIterator{contract: _VRFBeacon.contract, event: "OraclePaid", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- *VRFBeaconOraclePaid, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (event.Subscription, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var payeeRule []interface{} - for _, payeeItem := range payee { - payeeRule = append(payeeRule, payeeItem) - } - - var linkTokenRule []interface{} - for _, linkTokenItem := range linkToken { - linkTokenRule = append(linkTokenRule, linkTokenItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "OraclePaid", transmitterRule, payeeRule, linkTokenRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconOraclePaid) - if err := _VRFBeacon.contract.UnpackLog(event, "OraclePaid", 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 (_VRFBeacon *VRFBeaconFilterer) ParseOraclePaid(log types.Log) (*VRFBeaconOraclePaid, error) { - event := new(VRFBeaconOraclePaid) - if err := _VRFBeacon.contract.UnpackLog(event, "OraclePaid", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconOutputsServedIterator struct { - Event *VRFBeaconOutputsServed - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconOutputsServedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconOutputsServed) - 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(VRFBeaconOutputsServed) - 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 *VRFBeaconOutputsServedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconOutputsServedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconOutputsServed struct { - RecentBlockHeight uint64 - JuelsPerFeeCoin *big.Int - ReasonableGasPrice uint64 - OutputsServed []VRFBeaconTypesOutputServed - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterOutputsServed(opts *bind.FilterOpts) (*VRFBeaconOutputsServedIterator, error) { - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "OutputsServed") - if err != nil { - return nil, err - } - return &VRFBeaconOutputsServedIterator{contract: _VRFBeacon.contract, event: "OutputsServed", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *VRFBeaconOutputsServed) (event.Subscription, error) { - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "OutputsServed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconOutputsServed) - if err := _VRFBeacon.contract.UnpackLog(event, "OutputsServed", 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 (_VRFBeacon *VRFBeaconFilterer) ParseOutputsServed(log types.Log) (*VRFBeaconOutputsServed, error) { - event := new(VRFBeaconOutputsServed) - if err := _VRFBeacon.contract.UnpackLog(event, "OutputsServed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconOwnershipTransferRequestedIterator struct { - Event *VRFBeaconOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconOwnershipTransferRequested) - 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(VRFBeaconOwnershipTransferRequested) - 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 *VRFBeaconOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFBeaconOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFBeaconOwnershipTransferRequestedIterator{contract: _VRFBeacon.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconOwnershipTransferRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFBeaconOwnershipTransferRequested, error) { - event := new(VRFBeaconOwnershipTransferRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconOwnershipTransferredIterator struct { - Event *VRFBeaconOwnershipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconOwnershipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconOwnershipTransferred) - 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(VRFBeaconOwnershipTransferred) - 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 *VRFBeaconOwnershipTransferredIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFBeaconOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFBeaconOwnershipTransferredIterator{contract: _VRFBeacon.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFBeaconOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconOwnershipTransferred) - if err := _VRFBeacon.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParseOwnershipTransferred(log types.Log) (*VRFBeaconOwnershipTransferred, error) { - event := new(VRFBeaconOwnershipTransferred) - if err := _VRFBeacon.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconPayeeshipTransferRequestedIterator struct { - Event *VRFBeaconPayeeshipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconPayeeshipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconPayeeshipTransferRequested) - 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(VRFBeaconPayeeshipTransferRequested) - 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 *VRFBeaconPayeeshipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconPayeeshipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconPayeeshipTransferRequested struct { - Transmitter common.Address - Current common.Address - Proposed common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, current []common.Address, proposed []common.Address) (*VRFBeaconPayeeshipTransferRequestedIterator, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var currentRule []interface{} - for _, currentItem := range current { - currentRule = append(currentRule, currentItem) - } - var proposedRule []interface{} - for _, proposedItem := range proposed { - proposedRule = append(proposedRule, proposedItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, currentRule, proposedRule) - if err != nil { - return nil, err - } - return &VRFBeaconPayeeshipTransferRequestedIterator{contract: _VRFBeacon.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconPayeeshipTransferRequested, transmitter []common.Address, current []common.Address, proposed []common.Address) (event.Subscription, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var currentRule []interface{} - for _, currentItem := range current { - currentRule = append(currentRule, currentItem) - } - var proposedRule []interface{} - for _, proposedItem := range proposed { - proposedRule = append(proposedRule, proposedItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, currentRule, proposedRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconPayeeshipTransferRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParsePayeeshipTransferRequested(log types.Log) (*VRFBeaconPayeeshipTransferRequested, error) { - event := new(VRFBeaconPayeeshipTransferRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconPayeeshipTransferredIterator struct { - Event *VRFBeaconPayeeshipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconPayeeshipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconPayeeshipTransferred) - 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(VRFBeaconPayeeshipTransferred) - 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 *VRFBeaconPayeeshipTransferredIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconPayeeshipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconPayeeshipTransferred struct { - Transmitter common.Address - Previous common.Address - Current common.Address - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, previous []common.Address, current []common.Address) (*VRFBeaconPayeeshipTransferredIterator, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var previousRule []interface{} - for _, previousItem := range previous { - previousRule = append(previousRule, previousItem) - } - var currentRule []interface{} - for _, currentItem := range current { - currentRule = append(currentRule, currentItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, previousRule, currentRule) - if err != nil { - return nil, err - } - return &VRFBeaconPayeeshipTransferredIterator{contract: _VRFBeacon.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *VRFBeaconPayeeshipTransferred, transmitter []common.Address, previous []common.Address, current []common.Address) (event.Subscription, error) { - - var transmitterRule []interface{} - for _, transmitterItem := range transmitter { - transmitterRule = append(transmitterRule, transmitterItem) - } - var previousRule []interface{} - for _, previousItem := range previous { - previousRule = append(previousRule, previousItem) - } - var currentRule []interface{} - for _, currentItem := range current { - currentRule = append(currentRule, currentItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, previousRule, currentRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconPayeeshipTransferred) - if err := _VRFBeacon.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParsePayeeshipTransferred(log types.Log) (*VRFBeaconPayeeshipTransferred, error) { - event := new(VRFBeaconPayeeshipTransferred) - if err := _VRFBeacon.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconRandomWordsFulfilledIterator struct { - Event *VRFBeaconRandomWordsFulfilled - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconRandomWordsFulfilledIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconRandomWordsFulfilled) - 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(VRFBeaconRandomWordsFulfilled) - 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 *VRFBeaconRandomWordsFulfilledIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconRandomWordsFulfilledIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconRandomWordsFulfilled struct { - RequestIDs []*big.Int - SuccessfulFulfillment []byte - TruncatedErrorData [][]byte - SubBalances []*big.Int - SubIDs []*big.Int - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*VRFBeaconRandomWordsFulfilledIterator, error) { - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "RandomWordsFulfilled") - if err != nil { - return nil, err - } - return &VRFBeaconRandomWordsFulfilledIterator{contract: _VRFBeacon.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomWordsFulfilled) (event.Subscription, error) { - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "RandomWordsFulfilled") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconRandomWordsFulfilled) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFBeacon *VRFBeaconFilterer) ParseRandomWordsFulfilled(log types.Log) (*VRFBeaconRandomWordsFulfilled, error) { - event := new(VRFBeaconRandomWordsFulfilled) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconRandomnessFulfillmentRequestedIterator struct { - Event *VRFBeaconRandomnessFulfillmentRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconRandomnessFulfillmentRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconRandomnessFulfillmentRequested) - 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(VRFBeaconRandomnessFulfillmentRequested) - 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 *VRFBeaconRandomnessFulfillmentRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconRandomnessFulfillmentRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconRandomnessFulfillmentRequested struct { - RequestID *big.Int - Requester common.Address - NextBeaconOutputHeight uint64 - ConfDelay *big.Int - SubID *big.Int - NumWords uint16 - GasAllowance uint32 - GasPrice *big.Int - WeiPerUnitLink *big.Int - Arguments []byte - CostJuels *big.Int - NewSubBalance *big.Int - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFBeaconRandomnessFulfillmentRequestedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "RandomnessFulfillmentRequested", requestIDRule) - if err != nil { - return nil, err - } - return &VRFBeaconRandomnessFulfillmentRequestedIterator{contract: _VRFBeacon.contract, event: "RandomnessFulfillmentRequested", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "RandomnessFulfillmentRequested", requestIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconRandomnessFulfillmentRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessFulfillmentRequested", 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 (_VRFBeacon *VRFBeaconFilterer) ParseRandomnessFulfillmentRequested(log types.Log) (*VRFBeaconRandomnessFulfillmentRequested, error) { - event := new(VRFBeaconRandomnessFulfillmentRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessFulfillmentRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconRandomnessRedeemedIterator struct { - Event *VRFBeaconRandomnessRedeemed - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconRandomnessRedeemedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconRandomnessRedeemed) - 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(VRFBeaconRandomnessRedeemed) - 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 *VRFBeaconRandomnessRedeemedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconRandomnessRedeemedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconRandomnessRedeemed struct { - RequestID *big.Int - Requester common.Address - SubID *big.Int - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*VRFBeaconRandomnessRedeemedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - var requesterRule []interface{} - for _, requesterItem := range requester { - requesterRule = append(requesterRule, requesterItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "RandomnessRedeemed", requestIDRule, requesterRule) - if err != nil { - return nil, err - } - return &VRFBeaconRandomnessRedeemedIterator{contract: _VRFBeacon.contract, event: "RandomnessRedeemed", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - var requesterRule []interface{} - for _, requesterItem := range requester { - requesterRule = append(requesterRule, requesterItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "RandomnessRedeemed", requestIDRule, requesterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconRandomnessRedeemed) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessRedeemed", 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 (_VRFBeacon *VRFBeaconFilterer) ParseRandomnessRedeemed(log types.Log) (*VRFBeaconRandomnessRedeemed, error) { - event := new(VRFBeaconRandomnessRedeemed) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessRedeemed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFBeaconRandomnessRequestedIterator struct { - Event *VRFBeaconRandomnessRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFBeaconRandomnessRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFBeaconRandomnessRequested) - 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(VRFBeaconRandomnessRequested) - 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 *VRFBeaconRandomnessRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFBeaconRandomnessRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFBeaconRandomnessRequested struct { - RequestID *big.Int - Requester common.Address - NextBeaconOutputHeight uint64 - ConfDelay *big.Int - SubID *big.Int - NumWords uint16 - CostJuels *big.Int - NewSubBalance *big.Int - Raw types.Log -} - -func (_VRFBeacon *VRFBeaconFilterer) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFBeaconRandomnessRequestedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFBeacon.contract.FilterLogs(opts, "RandomnessRequested", requestIDRule) - if err != nil { - return nil, err - } - return &VRFBeaconRandomnessRequestedIterator{contract: _VRFBeacon.contract, event: "RandomnessRequested", logs: logs, sub: sub}, nil -} - -func (_VRFBeacon *VRFBeaconFilterer) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFBeacon.contract.WatchLogs(opts, "RandomnessRequested", requestIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFBeaconRandomnessRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessRequested", 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 (_VRFBeacon *VRFBeaconFilterer) ParseRandomnessRequested(log types.Log) (*VRFBeaconRandomnessRequested, error) { - event := new(VRFBeaconRandomnessRequested) - if err := _VRFBeacon.contract.UnpackLog(event, "RandomnessRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type GetBilling struct { - MaximumGasPrice uint64 - ReasonableGasPrice uint64 - ObservationPayment uint64 - TransmissionPayment uint64 - AccountingGas *big.Int -} -type LatestConfigDetails struct { - ConfigCount uint32 - BlockNumber uint32 - ConfigDigest [32]byte -} -type LatestConfigDigestAndEpoch struct { - ScanLogs bool - ConfigDigest [32]byte - Epoch uint32 -} - -func (_VRFBeacon *VRFBeacon) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _VRFBeacon.abi.Events["BillingAccessControllerSet"].ID: - return _VRFBeacon.ParseBillingAccessControllerSet(log) - case _VRFBeacon.abi.Events["BillingSet"].ID: - return _VRFBeacon.ParseBillingSet(log) - case _VRFBeacon.abi.Events["ConfigSet"].ID: - return _VRFBeacon.ParseConfigSet(log) - case _VRFBeacon.abi.Events["NewTransmission"].ID: - return _VRFBeacon.ParseNewTransmission(log) - case _VRFBeacon.abi.Events["OraclePaid"].ID: - return _VRFBeacon.ParseOraclePaid(log) - case _VRFBeacon.abi.Events["OutputsServed"].ID: - return _VRFBeacon.ParseOutputsServed(log) - case _VRFBeacon.abi.Events["OwnershipTransferRequested"].ID: - return _VRFBeacon.ParseOwnershipTransferRequested(log) - case _VRFBeacon.abi.Events["OwnershipTransferred"].ID: - return _VRFBeacon.ParseOwnershipTransferred(log) - case _VRFBeacon.abi.Events["PayeeshipTransferRequested"].ID: - return _VRFBeacon.ParsePayeeshipTransferRequested(log) - case _VRFBeacon.abi.Events["PayeeshipTransferred"].ID: - return _VRFBeacon.ParsePayeeshipTransferred(log) - case _VRFBeacon.abi.Events["RandomWordsFulfilled"].ID: - return _VRFBeacon.ParseRandomWordsFulfilled(log) - case _VRFBeacon.abi.Events["RandomnessFulfillmentRequested"].ID: - return _VRFBeacon.ParseRandomnessFulfillmentRequested(log) - case _VRFBeacon.abi.Events["RandomnessRedeemed"].ID: - return _VRFBeacon.ParseRandomnessRedeemed(log) - case _VRFBeacon.abi.Events["RandomnessRequested"].ID: - return _VRFBeacon.ParseRandomnessRequested(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (VRFBeaconBillingAccessControllerSet) Topic() common.Hash { - return common.HexToHash("0x793cb73064f3c8cde7e187ae515511e6e56d1ee89bf08b82fa60fb70f8d48912") -} - -func (VRFBeaconBillingSet) Topic() common.Hash { - return common.HexToHash("0x49275ddcdfc9c0519b3d094308c8bf675f06070a754ce90c152163cb6e66e8a0") -} - -func (VRFBeaconConfigSet) Topic() common.Hash { - return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") -} - -func (VRFBeaconNewTransmission) Topic() common.Hash { - return common.HexToHash("0xfc3c7a7927e878a0fca37c904953c3c75cee3ca1d1640184a0ab1c65eec62743") -} - -func (VRFBeaconOraclePaid) Topic() common.Hash { - return common.HexToHash("0xd0b1dac935d85bd54cf0a33b0d41d39f8cf53a968465fc7ea2377526b8ac712c") -} - -func (VRFBeaconOutputsServed) Topic() common.Hash { - return common.HexToHash("0xf10ea936d00579b4c52035ee33bf46929646b3aa87554c565d8fb2c7aa549c44") -} - -func (VRFBeaconOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (VRFBeaconOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") -} - -func (VRFBeaconPayeeshipTransferRequested) Topic() common.Hash { - return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") -} - -func (VRFBeaconPayeeshipTransferred) Topic() common.Hash { - return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") -} - -func (VRFBeaconRandomWordsFulfilled) Topic() common.Hash { - return common.HexToHash("0x8f79f730779e875ce76c428039cc2052b5b5918c2a55c598fab251c1198aec54") -} - -func (VRFBeaconRandomnessFulfillmentRequested) Topic() common.Hash { - return common.HexToHash("0x01872fb9c7d6d68af06a17347935e04412da302a377224c205e672c26e18c37f") -} - -func (VRFBeaconRandomnessRedeemed) Topic() common.Hash { - return common.HexToHash("0x16f3f633197fafab10a5df69e6f3f2f7f20092f08d8d47de0a91c0f4b96a1a25") -} - -func (VRFBeaconRandomnessRequested) Topic() common.Hash { - return common.HexToHash("0xb7933fba96b6b452eb44f99fdc08052a45dff82363d59abaff0456931c3d2459") -} - -func (_VRFBeacon *VRFBeacon) Address() common.Address { - return _VRFBeacon.address -} - -type VRFBeaconInterface interface { - NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) - - GetBilling(opts *bind.CallOpts) (GetBilling, - - error) - - GetBillingAccessController(opts *bind.CallOpts) (common.Address, error) - - ICoordinator(opts *bind.CallOpts) (common.Address, error) - - ILink(opts *bind.CallOpts) (common.Address, error) - - LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, - - error) - - LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, - - error) - - LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) - - OwedPayment(opts *bind.CallOpts, transmitterAddress common.Address) (*big.Int, error) - - Owner(opts *bind.CallOpts) (common.Address, error) - - SKeyID(opts *bind.CallOpts) ([32]byte, error) - - SKeyProvider(opts *bind.CallOpts) (common.Address, error) - - SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) - - TypeAndVersion(opts *bind.CallOpts) (string, error) - - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - - AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) - - ExposeType(opts *bind.TransactOpts, arg0 VRFBeaconReportReport) (*types.Transaction, error) - - KeyGenerated(opts *bind.TransactOpts, kd KeyDataStructKeyData) (*types.Transaction, error) - - NewKeyRequested(opts *bind.TransactOpts) (*types.Transaction, error) - - SetBilling(opts *bind.TransactOpts, maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) - - SetBillingAccessController(opts *bind.TransactOpts, _billingAccessController common.Address) (*types.Transaction, error) - - SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) - - SetPayees(opts *bind.TransactOpts, transmitters []common.Address, payees []common.Address) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - - TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) - - Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) - - WithdrawFunds(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) - - WithdrawPayment(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) - - FilterBillingAccessControllerSet(opts *bind.FilterOpts) (*VRFBeaconBillingAccessControllerSetIterator, error) - - WatchBillingAccessControllerSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconBillingAccessControllerSet) (event.Subscription, error) - - ParseBillingAccessControllerSet(log types.Log) (*VRFBeaconBillingAccessControllerSet, error) - - FilterBillingSet(opts *bind.FilterOpts) (*VRFBeaconBillingSetIterator, error) - - WatchBillingSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconBillingSet) (event.Subscription, error) - - ParseBillingSet(log types.Log) (*VRFBeaconBillingSet, error) - - FilterConfigSet(opts *bind.FilterOpts) (*VRFBeaconConfigSetIterator, error) - - WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFBeaconConfigSet) (event.Subscription, error) - - ParseConfigSet(log types.Log) (*VRFBeaconConfigSet, error) - - FilterNewTransmission(opts *bind.FilterOpts, epochAndRound []*big.Int) (*VRFBeaconNewTransmissionIterator, error) - - WatchNewTransmission(opts *bind.WatchOpts, sink chan<- *VRFBeaconNewTransmission, epochAndRound []*big.Int) (event.Subscription, error) - - ParseNewTransmission(log types.Log) (*VRFBeaconNewTransmission, error) - - FilterOraclePaid(opts *bind.FilterOpts, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (*VRFBeaconOraclePaidIterator, error) - - WatchOraclePaid(opts *bind.WatchOpts, sink chan<- *VRFBeaconOraclePaid, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (event.Subscription, error) - - ParseOraclePaid(log types.Log) (*VRFBeaconOraclePaid, error) - - FilterOutputsServed(opts *bind.FilterOpts) (*VRFBeaconOutputsServedIterator, error) - - WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *VRFBeaconOutputsServed) (event.Subscription, error) - - ParseOutputsServed(log types.Log) (*VRFBeaconOutputsServed, error) - - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFBeaconOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferRequested(log types.Log) (*VRFBeaconOwnershipTransferRequested, error) - - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFBeaconOwnershipTransferredIterator, error) - - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFBeaconOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferred(log types.Log) (*VRFBeaconOwnershipTransferred, error) - - FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, current []common.Address, proposed []common.Address) (*VRFBeaconPayeeshipTransferRequestedIterator, error) - - WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconPayeeshipTransferRequested, transmitter []common.Address, current []common.Address, proposed []common.Address) (event.Subscription, error) - - ParsePayeeshipTransferRequested(log types.Log) (*VRFBeaconPayeeshipTransferRequested, error) - - FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, previous []common.Address, current []common.Address) (*VRFBeaconPayeeshipTransferredIterator, error) - - WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *VRFBeaconPayeeshipTransferred, transmitter []common.Address, previous []common.Address, current []common.Address) (event.Subscription, error) - - ParsePayeeshipTransferred(log types.Log) (*VRFBeaconPayeeshipTransferred, error) - - FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*VRFBeaconRandomWordsFulfilledIterator, error) - - WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomWordsFulfilled) (event.Subscription, error) - - ParseRandomWordsFulfilled(log types.Log) (*VRFBeaconRandomWordsFulfilled, error) - - FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFBeaconRandomnessFulfillmentRequestedIterator, error) - - WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) - - ParseRandomnessFulfillmentRequested(log types.Log) (*VRFBeaconRandomnessFulfillmentRequested, error) - - FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*VRFBeaconRandomnessRedeemedIterator, error) - - WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) - - ParseRandomnessRedeemed(log types.Log) (*VRFBeaconRandomnessRedeemed, error) - - FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFBeaconRandomnessRequestedIterator, error) - - WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *VRFBeaconRandomnessRequested, requestID []*big.Int) (event.Subscription, error) - - ParseRandomnessRequested(log types.Log) (*VRFBeaconRandomnessRequested, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer/vrf_beacon_consumer.go b/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer/vrf_beacon_consumer.go deleted file mode 100644 index edc4ec6556d..00000000000 --- a/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer/vrf_beacon_consumer.go +++ /dev/null @@ -1,1034 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package vrf_beacon_consumer - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -var BeaconVRFConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"shouldFail\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"beaconPeriodBlocks\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"MustBeCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeOwnerOrCoordinator\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fail\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_beaconPeriodBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_ReceivedRandomnessByRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_arguments\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_mostRecentRequestID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_myBeaconRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"slotNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"s_requestsIDs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"shouldFail\",\"type\":\"bool\"}],\"name\":\"setFail\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"reqId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"delay\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"}],\"name\":\"storeBeaconRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"}],\"name\":\"testRedeemRandomness\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelayArg\",\"type\":\"uint24\"}],\"name\":\"testRequestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"}],\"name\":\"testRequestRandomnessFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620018db380380620018db8339810160408190526200003491620001aa565b8233806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000ff565b5050600280546001600160a01b0319166001600160a01b03939093169290921790915550600b805460ff191692151592909217909155600c555062000201565b336001600160a01b03821603620001595760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080600060608486031215620001c057600080fd5b83516001600160a01b0381168114620001d857600080fd5b60208501519093508015158114620001ef57600080fd5b80925050604084015190509250925092565b6116ca80620002116000396000f3fe608060405234801561001057600080fd5b506004361061016c5760003560e01c8063a9cc4718116100cd578063ea7502ab11610081578063f2fde38b11610066578063f2fde38b1461031f578063f6eaffc814610332578063ffe97ca41461034557600080fd5b8063ea7502ab14610303578063f08c5daa1461031657600080fd5b8063cd0593df116100b2578063cd0593df146102d4578063d0705f04146102dd578063d21ea8fd146102f057600080fd5b8063a9cc4718146102a4578063c6d61301146102c157600080fd5b80637716cdaa116101245780638da5cb5b116101095780638da5cb5b1461022a5780638ea98117146102525780639d7694021461026557600080fd5b80637716cdaa1461020d57806379ba50971461022257600080fd5b8063689b77ab11610155578063689b77ab146101c45780636df57cc3146101cd578063706da1ca146101e057600080fd5b8063341867a2146101715780635f15cccc14610186575b600080fd5b61018461017f366004610e87565b6103f8565b005b6101b1610194366004610ec1565b600460209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101b160085481565b6101846101db366004610eff565b6104ed565b6009546101f49067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101bb565b610215610628565b6040516101bb9190610fa9565b6101846106b6565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bb565b610184610260366004610fc3565b6107b8565b610184610273366004610ff9565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b600b546102b19060ff1681565b60405190151581526020016101bb565b6101b16102cf36600461101b565b61089e565b6101b1600c5481565b6101b16102eb366004610e87565b6109a8565b6101846102fe366004611187565b6109d9565b6101b1610311366004611250565b610a3a565b6101b1600a5481565b61018461032d366004610fc3565b610b4a565b6101b16103403660046112d4565b610b5e565b6103ae6103533660046112d4565b60056020526000908152604090205463ffffffff811690640100000000810462ffffff1690670100000000000000810461ffff16906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1684565b6040805163ffffffff909516855262ffffff909316602085015261ffff9091169183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080016101bb565b60025460408051602081018252600080825291517facfc6cdd000000000000000000000000000000000000000000000000000000008152919273ffffffffffffffffffffffffffffffffffffffff169163acfc6cdd9161045e91879187916004016112ed565b6000604051808303816000875af115801561047d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c39190810190611315565b600083815260066020908152604090912082519293506104e7929091840190610e27565b50505050565b600083815260046020908152604080832062ffffff861684529091528120859055600c5461051b9085611404565b6040805160808101825263ffffffff928316815262ffffff958616602080830191825261ffff968716838501908152306060850190815260009b8c526005909252939099209151825491519351995173ffffffffffffffffffffffffffffffffffffffff166901000000000000000000027fffffff0000000000000000000000000000000000000000ffffffffffffffffff9a90971667010000000000000002999099167fffffff00000000000000000000000000000000000000000000ffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009091169890931697909717919091171692909217179092555050565b6007805461063590611418565b80601f016020809104026020016040519081016040528092919081815260200182805461066190611418565b80156106ae5780601f10610683576101008083540402835291602001916106ae565b820191906000526020600020905b81548152906001019060200180831161069157829003601f168201915b505050505081565b60015473ffffffffffffffffffffffffffffffffffffffff16331461073c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906107f8575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561082f576040517fd4e06fd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517fc258faa9a17ddfdf4130b4acff63a289202e7d5f9e42f366add65368575486bc90600090a250565b600080600c546108ac610b7f565b6108b6919061146b565b9050600081600c546108c6610b7f565b6108d0919061147f565b6108da9190611498565b60025460408051602081018252600080825291517f4ffac83a000000000000000000000000000000000000000000000000000000008152939450909273ffffffffffffffffffffffffffffffffffffffff90921691634ffac83a91610948918a918c918b91906004016114ab565b6020604051808303816000875af1158015610967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098b91906114e3565b90506109998183878a6104ed565b60088190559695505050505050565b600660205281600052604060002081815481106109c457600080fd5b90600052602060002001600091509150505481565b60025473ffffffffffffffffffffffffffffffffffffffff163314610a2a576040517f66bf9c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a35838383610c16565b505050565b600080600c54610a48610b7f565b610a52919061146b565b9050600081600c54610a62610b7f565b610a6c919061147f565b610a769190611498565b60025460408051602081018252600080825291517fdb972c8b000000000000000000000000000000000000000000000000000000008152939450909273ffffffffffffffffffffffffffffffffffffffff9092169163db972c8b91610ae8918d918d918d918d918d91906004016114fc565b6020604051808303816000875af1158015610b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2b91906114e3565b9050610b398183898b6104ed565b600881905598975050505050505050565b610b52610caf565b610b5b81610d32565b50565b60038181548110610b6e57600080fd5b600091825260209091200154905081565b60004661a4b1811480610b94575062066eed81145b15610c0f57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0991906114e3565b91505090565b4391505090565b600b5460ff1615610c83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f206661696c656420696e2066756c66696c6c52616e646f6d576f7264730000006044820152606401610733565b60008381526006602090815260409091208351610ca292850190610e27565b5060076104e782826115a3565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610733565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610733565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e62579160200282015b82811115610e62578251825591602001919060010190610e47565b50610e6e929150610e72565b5090565b5b80821115610e6e5760008155600101610e73565b60008060408385031215610e9a57600080fd5b50508035926020909101359150565b803562ffffff81168114610ebc57600080fd5b919050565b60008060408385031215610ed457600080fd5b82359150610ee460208401610ea9565b90509250929050565b803561ffff81168114610ebc57600080fd5b60008060008060808587031215610f1557600080fd5b8435935060208501359250610f2c60408601610ea9565b9150610f3a60608601610eed565b905092959194509250565b6000815180845260005b81811015610f6b57602081850181015186830182015201610f4f565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610fbc6020830184610f45565b9392505050565b600060208284031215610fd557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610fbc57600080fd5b60006020828403121561100b57600080fd5b81358015158114610fbc57600080fd5b60008060006060848603121561103057600080fd5b61103984610eed565b92506020840135915061104e60408501610ea9565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156110cd576110cd611057565b604052919050565b600067ffffffffffffffff8211156110ef576110ef611057565b5060051b60200190565b600082601f83011261110a57600080fd5b813567ffffffffffffffff81111561112457611124611057565b61115560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611086565b81815284602083860101111561116a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561119c57600080fd5b8335925060208085013567ffffffffffffffff808211156111bc57600080fd5b818701915087601f8301126111d057600080fd5b81356111e36111de826110d5565b611086565b81815260059190911b8301840190848101908a83111561120257600080fd5b938501935b8285101561122057843582529385019390850190611207565b96505050604087013592508083111561123857600080fd5b5050611246868287016110f9565b9150509250925092565b600080600080600060a0868803121561126857600080fd5b8535945061127860208701610eed565b935061128660408701610ea9565b9250606086013563ffffffff8116811461129f57600080fd5b9150608086013567ffffffffffffffff8111156112bb57600080fd5b6112c7888289016110f9565b9150509295509295909350565b6000602082840312156112e657600080fd5b5035919050565b83815282602082015260606040820152600061130c6060830184610f45565b95945050505050565b6000602080838503121561132857600080fd5b825167ffffffffffffffff81111561133f57600080fd5b8301601f8101851361135057600080fd5b805161135e6111de826110d5565b81815260059190911b8201830190838101908783111561137d57600080fd5b928401925b8284101561139b57835182529284019290840190611382565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082611413576114136113a6565b500490565b600181811c9082168061142c57607f821691505b602082108103611465577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008261147a5761147a6113a6565b500690565b80820180821115611492576114926113d5565b92915050565b81810381811115611492576114926113d5565b84815261ffff8416602082015262ffffff831660408201526080606082015260006114d96080830184610f45565b9695505050505050565b6000602082840312156114f557600080fd5b5051919050565b86815261ffff8616602082015262ffffff8516604082015263ffffffff8416606082015260c06080820152600061153660c0830185610f45565b82810360a08401526115488185610f45565b9998505050505050505050565b601f821115610a3557600081815260208120601f850160051c8101602086101561157c5750805b601f850160051c820191505b8181101561159b57828155600101611588565b505050505050565b815167ffffffffffffffff8111156115bd576115bd611057565b6115d1816115cb8454611418565b84611555565b602080601f83116001811461162457600084156115ee5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561159b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561167157888601518255948401946001909101908401611652565b50858210156116ad57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000813000a", -} - -var BeaconVRFConsumerABI = BeaconVRFConsumerMetaData.ABI - -var BeaconVRFConsumerBin = BeaconVRFConsumerMetaData.Bin - -func DeployBeaconVRFConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, coordinator common.Address, shouldFail bool, beaconPeriodBlocks *big.Int) (common.Address, *types.Transaction, *BeaconVRFConsumer, error) { - parsed, err := BeaconVRFConsumerMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BeaconVRFConsumerBin), backend, coordinator, shouldFail, beaconPeriodBlocks) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &BeaconVRFConsumer{BeaconVRFConsumerCaller: BeaconVRFConsumerCaller{contract: contract}, BeaconVRFConsumerTransactor: BeaconVRFConsumerTransactor{contract: contract}, BeaconVRFConsumerFilterer: BeaconVRFConsumerFilterer{contract: contract}}, nil -} - -type BeaconVRFConsumer struct { - address common.Address - abi abi.ABI - BeaconVRFConsumerCaller - BeaconVRFConsumerTransactor - BeaconVRFConsumerFilterer -} - -type BeaconVRFConsumerCaller struct { - contract *bind.BoundContract -} - -type BeaconVRFConsumerTransactor struct { - contract *bind.BoundContract -} - -type BeaconVRFConsumerFilterer struct { - contract *bind.BoundContract -} - -type BeaconVRFConsumerSession struct { - Contract *BeaconVRFConsumer - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type BeaconVRFConsumerCallerSession struct { - Contract *BeaconVRFConsumerCaller - CallOpts bind.CallOpts -} - -type BeaconVRFConsumerTransactorSession struct { - Contract *BeaconVRFConsumerTransactor - TransactOpts bind.TransactOpts -} - -type BeaconVRFConsumerRaw struct { - Contract *BeaconVRFConsumer -} - -type BeaconVRFConsumerCallerRaw struct { - Contract *BeaconVRFConsumerCaller -} - -type BeaconVRFConsumerTransactorRaw struct { - Contract *BeaconVRFConsumerTransactor -} - -func NewBeaconVRFConsumer(address common.Address, backend bind.ContractBackend) (*BeaconVRFConsumer, error) { - abi, err := abi.JSON(strings.NewReader(BeaconVRFConsumerABI)) - if err != nil { - return nil, err - } - contract, err := bindBeaconVRFConsumer(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &BeaconVRFConsumer{address: address, abi: abi, BeaconVRFConsumerCaller: BeaconVRFConsumerCaller{contract: contract}, BeaconVRFConsumerTransactor: BeaconVRFConsumerTransactor{contract: contract}, BeaconVRFConsumerFilterer: BeaconVRFConsumerFilterer{contract: contract}}, nil -} - -func NewBeaconVRFConsumerCaller(address common.Address, caller bind.ContractCaller) (*BeaconVRFConsumerCaller, error) { - contract, err := bindBeaconVRFConsumer(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerCaller{contract: contract}, nil -} - -func NewBeaconVRFConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*BeaconVRFConsumerTransactor, error) { - contract, err := bindBeaconVRFConsumer(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerTransactor{contract: contract}, nil -} - -func NewBeaconVRFConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*BeaconVRFConsumerFilterer, error) { - contract, err := bindBeaconVRFConsumer(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerFilterer{contract: contract}, nil -} - -func bindBeaconVRFConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := BeaconVRFConsumerMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _BeaconVRFConsumer.Contract.BeaconVRFConsumerCaller.contract.Call(opts, result, method, params...) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.BeaconVRFConsumerTransactor.contract.Transfer(opts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.BeaconVRFConsumerTransactor.contract.Transact(opts, method, params...) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _BeaconVRFConsumer.Contract.contract.Call(opts, result, method, params...) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.contract.Transfer(opts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.contract.Transact(opts, method, params...) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) Fail(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "fail") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) Fail() (bool, error) { - return _BeaconVRFConsumer.Contract.Fail(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) Fail() (bool, error) { - return _BeaconVRFConsumer.Contract.Fail(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "i_beaconPeriodBlocks") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.IBeaconPeriodBlocks(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.IBeaconPeriodBlocks(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) Owner() (common.Address, error) { - return _BeaconVRFConsumer.Contract.Owner(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) Owner() (common.Address, error) { - return _BeaconVRFConsumer.Contract.Owner(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SReceivedRandomnessByRequestID(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_ReceivedRandomnessByRequestID", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SReceivedRandomnessByRequestID(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SReceivedRandomnessByRequestID(&_BeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SReceivedRandomnessByRequestID(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SReceivedRandomnessByRequestID(&_BeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SArguments(opts *bind.CallOpts) ([]byte, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_arguments") - - if err != nil { - return *new([]byte), err - } - - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SArguments() ([]byte, error) { - return _BeaconVRFConsumer.Contract.SArguments(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SArguments() ([]byte, error) { - return _BeaconVRFConsumer.Contract.SArguments(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SGasAvailable(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_gasAvailable") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SGasAvailable() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SGasAvailable(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SGasAvailable() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SGasAvailable(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SMostRecentRequestID(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_mostRecentRequestID") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SMostRecentRequestID() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SMostRecentRequestID(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SMostRecentRequestID() (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SMostRecentRequestID(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SMyBeaconRequests(opts *bind.CallOpts, arg0 *big.Int) (SMyBeaconRequests, - - error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_myBeaconRequests", arg0) - - outstruct := new(SMyBeaconRequests) - if err != nil { - return *outstruct, err - } - - outstruct.SlotNumber = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.ConfirmationDelay = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.NumWords = *abi.ConvertType(out[2], new(uint16)).(*uint16) - outstruct.Requester = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) - - return *outstruct, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SMyBeaconRequests(arg0 *big.Int) (SMyBeaconRequests, - - error) { - return _BeaconVRFConsumer.Contract.SMyBeaconRequests(&_BeaconVRFConsumer.CallOpts, arg0) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SMyBeaconRequests(arg0 *big.Int) (SMyBeaconRequests, - - error) { - return _BeaconVRFConsumer.Contract.SMyBeaconRequests(&_BeaconVRFConsumer.CallOpts, arg0) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SRandomWords(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_randomWords", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SRandomWords(arg0 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SRandomWords(&_BeaconVRFConsumer.CallOpts, arg0) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SRandomWords(arg0 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SRandomWords(&_BeaconVRFConsumer.CallOpts, arg0) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SRequestsIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_requestsIDs", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SRequestsIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SRequestsIDs(&_BeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SRequestsIDs(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _BeaconVRFConsumer.Contract.SRequestsIDs(&_BeaconVRFConsumer.CallOpts, arg0, arg1) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCaller) SSubId(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _BeaconVRFConsumer.contract.Call(opts, &out, "s_subId") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SSubId() (uint64, error) { - return _BeaconVRFConsumer.Contract.SSubId(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerCallerSession) SSubId() (uint64, error) { - return _BeaconVRFConsumer.Contract.SSubId(&_BeaconVRFConsumer.CallOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "acceptOwnership") -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) AcceptOwnership() (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.AcceptOwnership(&_BeaconVRFConsumer.TransactOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.AcceptOwnership(&_BeaconVRFConsumer.TransactOpts) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "rawFulfillRandomWords", requestID, randomWords, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) RawFulfillRandomWords(requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.RawFulfillRandomWords(&_BeaconVRFConsumer.TransactOpts, requestID, randomWords, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) RawFulfillRandomWords(requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.RawFulfillRandomWords(&_BeaconVRFConsumer.TransactOpts, requestID, randomWords, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) SetCoordinator(opts *bind.TransactOpts, coordinator common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "setCoordinator", coordinator) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SetCoordinator(coordinator common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.SetCoordinator(&_BeaconVRFConsumer.TransactOpts, coordinator) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) SetCoordinator(coordinator common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.SetCoordinator(&_BeaconVRFConsumer.TransactOpts, coordinator) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) SetFail(opts *bind.TransactOpts, shouldFail bool) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "setFail", shouldFail) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) SetFail(shouldFail bool) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.SetFail(&_BeaconVRFConsumer.TransactOpts, shouldFail) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) SetFail(shouldFail bool) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.SetFail(&_BeaconVRFConsumer.TransactOpts, shouldFail) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) StoreBeaconRequest(opts *bind.TransactOpts, reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "storeBeaconRequest", reqId, height, delay, numWords) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) StoreBeaconRequest(reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.StoreBeaconRequest(&_BeaconVRFConsumer.TransactOpts, reqId, height, delay, numWords) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) StoreBeaconRequest(reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.StoreBeaconRequest(&_BeaconVRFConsumer.TransactOpts, reqId, height, delay, numWords) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) TestRedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "testRedeemRandomness", subID, requestID) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) TestRedeemRandomness(subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRedeemRandomness(&_BeaconVRFConsumer.TransactOpts, subID, requestID) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) TestRedeemRandomness(subID *big.Int, requestID *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRedeemRandomness(&_BeaconVRFConsumer.TransactOpts, subID, requestID) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) TestRequestRandomness(opts *bind.TransactOpts, numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "testRequestRandomness", numWords, subID, confirmationDelayArg) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) TestRequestRandomness(numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRequestRandomness(&_BeaconVRFConsumer.TransactOpts, numWords, subID, confirmationDelayArg) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) TestRequestRandomness(numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRequestRandomness(&_BeaconVRFConsumer.TransactOpts, numWords, subID, confirmationDelayArg) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) TestRequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "testRequestRandomnessFulfillment", subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) TestRequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRequestRandomnessFulfillment(&_BeaconVRFConsumer.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) TestRequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TestRequestRandomnessFulfillment(&_BeaconVRFConsumer.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.contract.Transact(opts, "transferOwnership", to) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TransferOwnership(&_BeaconVRFConsumer.TransactOpts, to) -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _BeaconVRFConsumer.Contract.TransferOwnership(&_BeaconVRFConsumer.TransactOpts, to) -} - -type BeaconVRFConsumerCoordinatorUpdatedIterator struct { - Event *BeaconVRFConsumerCoordinatorUpdated - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *BeaconVRFConsumerCoordinatorUpdatedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(BeaconVRFConsumerCoordinatorUpdated) - 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(BeaconVRFConsumerCoordinatorUpdated) - 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 *BeaconVRFConsumerCoordinatorUpdatedIterator) Error() error { - return it.fail -} - -func (it *BeaconVRFConsumerCoordinatorUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type BeaconVRFConsumerCoordinatorUpdated struct { - Coordinator common.Address - Raw types.Log -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) FilterCoordinatorUpdated(opts *bind.FilterOpts, coordinator []common.Address) (*BeaconVRFConsumerCoordinatorUpdatedIterator, error) { - - var coordinatorRule []interface{} - for _, coordinatorItem := range coordinator { - coordinatorRule = append(coordinatorRule, coordinatorItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.FilterLogs(opts, "CoordinatorUpdated", coordinatorRule) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerCoordinatorUpdatedIterator{contract: _BeaconVRFConsumer.contract, event: "CoordinatorUpdated", logs: logs, sub: sub}, nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) WatchCoordinatorUpdated(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerCoordinatorUpdated, coordinator []common.Address) (event.Subscription, error) { - - var coordinatorRule []interface{} - for _, coordinatorItem := range coordinator { - coordinatorRule = append(coordinatorRule, coordinatorItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.WatchLogs(opts, "CoordinatorUpdated", coordinatorRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(BeaconVRFConsumerCoordinatorUpdated) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "CoordinatorUpdated", 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 (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) ParseCoordinatorUpdated(log types.Log) (*BeaconVRFConsumerCoordinatorUpdated, error) { - event := new(BeaconVRFConsumerCoordinatorUpdated) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "CoordinatorUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type BeaconVRFConsumerOwnershipTransferRequestedIterator struct { - Event *BeaconVRFConsumerOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *BeaconVRFConsumerOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(BeaconVRFConsumerOwnershipTransferRequested) - 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(BeaconVRFConsumerOwnershipTransferRequested) - 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 *BeaconVRFConsumerOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *BeaconVRFConsumerOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type BeaconVRFConsumerOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BeaconVRFConsumerOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerOwnershipTransferRequestedIterator{contract: _BeaconVRFConsumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(BeaconVRFConsumerOwnershipTransferRequested) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*BeaconVRFConsumerOwnershipTransferRequested, error) { - event := new(BeaconVRFConsumerOwnershipTransferRequested) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type BeaconVRFConsumerOwnershipTransferredIterator struct { - Event *BeaconVRFConsumerOwnershipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *BeaconVRFConsumerOwnershipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(BeaconVRFConsumerOwnershipTransferred) - 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(BeaconVRFConsumerOwnershipTransferred) - 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 *BeaconVRFConsumerOwnershipTransferredIterator) Error() error { - return it.fail -} - -func (it *BeaconVRFConsumerOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type BeaconVRFConsumerOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BeaconVRFConsumerOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &BeaconVRFConsumerOwnershipTransferredIterator{contract: _BeaconVRFConsumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _BeaconVRFConsumer.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(BeaconVRFConsumerOwnershipTransferred) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_BeaconVRFConsumer *BeaconVRFConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*BeaconVRFConsumerOwnershipTransferred, error) { - event := new(BeaconVRFConsumerOwnershipTransferred) - if err := _BeaconVRFConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type SMyBeaconRequests struct { - SlotNumber uint32 - ConfirmationDelay *big.Int - NumWords uint16 - Requester common.Address -} - -func (_BeaconVRFConsumer *BeaconVRFConsumer) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _BeaconVRFConsumer.abi.Events["CoordinatorUpdated"].ID: - return _BeaconVRFConsumer.ParseCoordinatorUpdated(log) - case _BeaconVRFConsumer.abi.Events["OwnershipTransferRequested"].ID: - return _BeaconVRFConsumer.ParseOwnershipTransferRequested(log) - case _BeaconVRFConsumer.abi.Events["OwnershipTransferred"].ID: - return _BeaconVRFConsumer.ParseOwnershipTransferred(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (BeaconVRFConsumerCoordinatorUpdated) Topic() common.Hash { - return common.HexToHash("0xc258faa9a17ddfdf4130b4acff63a289202e7d5f9e42f366add65368575486bc") -} - -func (BeaconVRFConsumerOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (BeaconVRFConsumerOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") -} - -func (_BeaconVRFConsumer *BeaconVRFConsumer) Address() common.Address { - return _BeaconVRFConsumer.address -} - -type BeaconVRFConsumerInterface interface { - Fail(opts *bind.CallOpts) (bool, error) - - IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) - - Owner(opts *bind.CallOpts) (common.Address, error) - - SReceivedRandomnessByRequestID(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SArguments(opts *bind.CallOpts) ([]byte, error) - - SGasAvailable(opts *bind.CallOpts) (*big.Int, error) - - SMostRecentRequestID(opts *bind.CallOpts) (*big.Int, error) - - SMyBeaconRequests(opts *bind.CallOpts, arg0 *big.Int) (SMyBeaconRequests, - - error) - - SRandomWords(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) - - SRequestsIDs(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) - - SSubId(opts *bind.CallOpts) (uint64, error) - - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - - RawFulfillRandomWords(opts *bind.TransactOpts, requestID *big.Int, randomWords []*big.Int, arguments []byte) (*types.Transaction, error) - - SetCoordinator(opts *bind.TransactOpts, coordinator common.Address) (*types.Transaction, error) - - SetFail(opts *bind.TransactOpts, shouldFail bool) (*types.Transaction, error) - - StoreBeaconRequest(opts *bind.TransactOpts, reqId *big.Int, height *big.Int, delay *big.Int, numWords uint16) (*types.Transaction, error) - - TestRedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int) (*types.Transaction, error) - - TestRequestRandomness(opts *bind.TransactOpts, numWords uint16, subID *big.Int, confirmationDelayArg *big.Int) (*types.Transaction, error) - - TestRequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - - FilterCoordinatorUpdated(opts *bind.FilterOpts, coordinator []common.Address) (*BeaconVRFConsumerCoordinatorUpdatedIterator, error) - - WatchCoordinatorUpdated(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerCoordinatorUpdated, coordinator []common.Address) (event.Subscription, error) - - ParseCoordinatorUpdated(log types.Log) (*BeaconVRFConsumerCoordinatorUpdated, error) - - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BeaconVRFConsumerOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferRequested(log types.Log) (*BeaconVRFConsumerOwnershipTransferRequested, error) - - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BeaconVRFConsumerOwnershipTransferredIterator, error) - - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BeaconVRFConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferred(log types.Log) (*BeaconVRFConsumerOwnershipTransferred, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/ocr2vrf/generated/vrf_coordinator/vrf_coordinator.go b/core/gethwrappers/ocr2vrf/generated/vrf_coordinator/vrf_coordinator.go deleted file mode 100644 index f20d5494452..00000000000 --- a/core/gethwrappers/ocr2vrf/generated/vrf_coordinator/vrf_coordinator.go +++ /dev/null @@ -1,3870 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package vrf_coordinator - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -type ECCArithmeticG1Point struct { - P [2]*big.Int -} - -type VRFBeaconTypesCallback struct { - RequestID *big.Int - NumWords uint16 - Requester common.Address - Arguments []byte - GasAllowance *big.Int - SubID *big.Int - GasPrice *big.Int - WeiPerUnitLink *big.Int -} - -type VRFBeaconTypesCoordinatorConfig struct { - UseReasonableGasPrice bool - ReentrancyLock bool - Paused bool - PremiumPercentage uint8 - UnusedGasPenaltyPercent uint8 - StalenessSeconds uint32 - RedeemableRequestGasOverhead uint32 - CallbackRequestGasOverhead uint32 - ReasonableGasPriceStalenessBlocks uint32 - FallbackWeiPerUnitLink *big.Int -} - -type VRFBeaconTypesCostedCallback struct { - Callback VRFBeaconTypesCallback - Price *big.Int -} - -type VRFBeaconTypesOutputServed struct { - Height uint64 - ConfirmationDelay *big.Int - ProofG1X *big.Int - ProofG1Y *big.Int -} - -type VRFBeaconTypesVRFOutput struct { - BlockHeight uint64 - ConfirmationDelay *big.Int - VrfOutput ECCArithmeticG1Point - Callbacks []VRFBeaconTypesCostedCallback - ShouldStore bool -} - -type VRFCoordinatorCallbackConfig struct { - MaxCallbackGasLimit uint32 - MaxCallbackArgumentsLength uint32 -} - -var VRFCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"beaconPeriodBlocksArg\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BeaconPeriodMustBePositive\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestHeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"earliestAllowed\",\"type\":\"uint256\"}],\"name\":\"BlockTooRecent\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16[10]\",\"name\":\"confirmationDelays\",\"type\":\"uint16[10]\"},{\"internalType\":\"uint8\",\"name\":\"violatingIndex\",\"type\":\"uint8\"}],\"name\":\"ConfirmationDelaysNotIncreasing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ContractPaused\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLeft\",\"type\":\"uint256\"}],\"name\":\"GasAllowanceExceedsGasLeft\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"reportHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"separatorHeight\",\"type\":\"uint64\"}],\"name\":\"HistoryDomainSeparatorTooOld\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"actualBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requiredBalance\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedLength\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"actualLength\",\"type\":\"uint256\"}],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCoordinatorConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidJuelsConversion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numRecipients\",\"type\":\"uint256\"}],\"name\":\"InvalidNumberOfRecipients\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestedSubID\",\"type\":\"uint256\"}],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestedVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"coordinatorVersion\",\"type\":\"uint8\"}],\"name\":\"MigrationVersionMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeProducer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativePaymentGiven\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoWordsRequested\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16[10]\",\"name\":\"confDelays\",\"type\":\"uint16[10]\"}],\"name\":\"NonZeroDelayAfterZeroDelay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnMigrationNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"producer\",\"type\":\"address\"}],\"name\":\"ProducerAlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestHeight\",\"type\":\"uint256\"}],\"name\":\"RandomnessNotAvailable\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestHeight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"confDelay\",\"type\":\"uint256\"}],\"name\":\"RandomnessSeedNotFoundForCallbacks\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numRecipients\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numPayments\",\"type\":\"uint256\"}],\"name\":\"RecipientsPaymentsMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"expected\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"actual\",\"type\":\"address\"}],\"name\":\"ResponseMustBeRetrievedByRequester\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyRequestsReplaceContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManySlotsReplaceContract\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"max\",\"type\":\"uint256\"}],\"name\":\"TooManyWords\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockHeight\",\"type\":\"uint256\"}],\"name\":\"UniverseHasEndedBangBangBang\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCallbackArgumentsLength\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinator.CallbackConfig\",\"name\":\"newConfig\",\"type\":\"tuple\"}],\"name\":\"CallbackConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"useReasonableGasPrice\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"unusedGasPenaltyPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"redeemableRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"callbackRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"reasonableGasPriceStalenessBlocks\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structVRFBeaconTypes.CoordinatorConfig\",\"name\":\"coordinatorConfig\",\"type\":\"tuple\"}],\"name\":\"CoordinatorConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint8\",\"name\":\"newVersion\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"recentBlockHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"juelsPerFeeCoin\",\"type\":\"uint192\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"height\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint256\",\"name\":\"proofG1X\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"proofG1Y\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structVRFBeaconTypes.OutputServed[]\",\"name\":\"outputsServed\",\"type\":\"tuple[]\"}],\"name\":\"OutputsServed\",\"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\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"name\":\"PauseFlagChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"requestIDs\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"successfulFulfillment\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes[]\",\"name\":\"truncatedErrorData\",\"type\":\"bytes[]\"},{\"indexed\":false,\"internalType\":\"uint96[]\",\"name\":\"subBalances\",\"type\":\"uint96[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"subIDs\",\"type\":\"uint256[]\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nextBeaconOutputHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAllowance\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"weiPerUnitLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"costJuels\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newSubBalance\",\"type\":\"uint256\"}],\"name\":\"RandomnessFulfillmentRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"}],\"name\":\"RandomnessRedeemed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nextBeaconOutputHeight\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"costJuels\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newSubBalance\",\"type\":\"uint256\"}],\"name\":\"RandomnessRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NUM_CONF_DELAYS\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"paymentsInJuels\",\"type\":\"uint256[]\"}],\"name\":\"batchTransferLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"getCallbackMemo\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfirmationDelays\",\"outputs\":[{\"internalType\":\"uint24[8]\",\"name\":\"\",\"type\":\"uint24[8]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getFulfillmentFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"pendingFulfillments\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionLinkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_beaconPeriodBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_link\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIVRFMigration\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"encodedRequest\",\"type\":\"bytes\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"p\",\"type\":\"uint256[2]\"}],\"internalType\":\"structECCArithmetic.G1Point\",\"name\":\"vrfOutput\",\"type\":\"tuple\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"gasAllowance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weiPerUnitLink\",\"type\":\"uint256\"}],\"internalType\":\"structVRFBeaconTypes.Callback\",\"name\":\"callback\",\"type\":\"tuple\"},{\"internalType\":\"uint96\",\"name\":\"price\",\"type\":\"uint96\"}],\"internalType\":\"structVRFBeaconTypes.CostedCallback[]\",\"name\":\"callbacks\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"shouldStore\",\"type\":\"bool\"}],\"internalType\":\"structVRFBeaconTypes.VRFOutput[]\",\"name\":\"vrfOutputs\",\"type\":\"tuple[]\"},{\"internalType\":\"uint192\",\"name\":\"juelsPerFeeCoin\",\"type\":\"uint192\"},{\"internalType\":\"uint64\",\"name\":\"reasonableGasPrice\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"blockHeight\",\"type\":\"uint64\"}],\"name\":\"processVRFOutputs\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"containsNewOutputs\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"redeemRandomness\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"randomness\",\"type\":\"uint256[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"uint24\",\"name\":\"confDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"arguments\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"requestRandomnessFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_callbackConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCallbackArgumentsLength\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_coordinatorConfig\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"useReasonableGasPrice\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"unusedGasPenaltyPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"redeemableRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"callbackRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"reasonableGasPriceStalenessBlocks\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_pendingRequests\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"slotNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"confirmationDelay\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"numWords\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_producer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"maxCallbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCallbackArgumentsLength\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinator.CallbackConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setCallbackConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24[8]\",\"name\":\"confDelays\",\"type\":\"uint24[8]\"}],\"name\":\"setConfirmationDelays\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"useReasonableGasPrice\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"unusedGasPenaltyPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"redeemableRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"callbackRequestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"reasonableGasPriceStalenessBlocks\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"uint96\"}],\"internalType\":\"structVRFBeaconTypes.CoordinatorConfig\",\"name\":\"coordinatorConfig\",\"type\":\"tuple\"}],\"name\":\"setCoordinatorConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"pause\",\"type\":\"bool\"}],\"name\":\"setPauseFlag\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"producer\",\"type\":\"address\"}],\"name\":\"setProducer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"juelsAmount\",\"type\":\"uint256\"}],\"name\":\"transferLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b50604051620062f5380380620062f5833981016040819052620000349162000239565b8033806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf816200018e565b5050506001600160a01b03166080908152604080519182018152600080835260208301819052908201819052662386f26fc10000606090920191909152642386f26fc160b01b6006556004805463ffffffff60281b191668ffffffff00000000001790558290036200014457604051632abc297960e01b815260040160405180910390fd5b60a0829052600e805465ffffffffffff16906000620001638362000278565b91906101000a81548165ffffffffffff021916908365ffffffffffff160217905550505050620002ac565b336001600160a01b03821603620001e85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080604083850312156200024d57600080fd5b825160208401519092506001600160a01b03811681146200026d57600080fd5b809150509250929050565b600065ffffffffffff808316818103620002a257634e487b7160e01b600052601160045260246000fd5b6001019392505050565b60805160a051615fdd620003186000396000818161075f01528181611ca301528181613cb301528181613ce201528181613d1a015261430e01526000818161047501528181610bb501528181611a410152818161237b01528181612d610152612df60152615fdd6000f3fe6080604052600436106101d65760003560e01c806304104edb146101db5780630ae09540146101fd57806316f6ee9a1461021d578063294daa491461025d5780632b38bafc1461027f5780632f7527cc1461029f5780633e79167f146102b457806340d6bb82146102d457806347c3e2cb146102ea5780634ffac83a14610385578063597d2f3c146103985780635d06b4ab146103b657806364d51a2a146103d657806373433a2f146103fe57806376f2e3f41461041e57806379ba50971461044e5780637d253aff1461046357806385c64e11146104a45780638c7cba66146104c65780638da5cb5b146104e65780638da92e71146105045780638eef585f146105245780639e20103614610544578063a21a23e414610564578063a4c0ed3614610579578063acfc6cdd14610599578063b2a7cac5146105c6578063b79fa6f7146105e6578063bd58017f146106cd578063bec4c08c146106ed578063c3fbb6fd1461070d578063cb6317971461072d578063cd0593df1461074d578063ce3f471914610781578063dac83d29146107a1578063db972c8b146107c1578063dc311dd3146107d4578063e30afa4a14610804578063f2fde38b14610849578063f99b1d6814610869578063f9c45ced14610889575b600080fd5b3480156101e757600080fd5b506101fb6101f6366004614abd565b6108a9565b005b34801561020957600080fd5b506101fb610218366004614ae1565b610a5e565b34801561022957600080fd5b5061024a610238366004614b11565b6000908152600c602052604090205490565b6040519081526020015b60405180910390f35b34801561026957600080fd5b5060015b60405160ff9091168152602001610254565b34801561028b57600080fd5b506101fb61029a366004614abd565b610cc0565b3480156102ab57600080fd5b5061026d600881565b3480156102c057600080fd5b506101fb6102cf366004614b2a565b610d21565b3480156102e057600080fd5b5061024a6103e881565b3480156102f657600080fd5b50610348610305366004614b11565b60106020526000908152604090205463ffffffff811690600160201b810462ffffff1690600160381b810461ffff1690600160481b90046001600160a01b031684565b6040805163ffffffff909516855262ffffff909316602085015261ffff909116918301919091526001600160a01b03166060820152608001610254565b61024a610393366004614cac565b610dd2565b3480156103a457600080fd5b506002546001600160601b031661024a565b3480156103c257600080fd5b506101fb6103d1366004614abd565b610f7e565b3480156103e257600080fd5b506103eb606481565b60405161ffff9091168152602001610254565b34801561040a57600080fd5b506101fb610419366004614d57565b61102a565b34801561042a57600080fd5b5061043e610439366004614dd9565b611115565b6040519015158152602001610254565b34801561045a57600080fd5b506101fb611453565b34801561046f57600080fd5b506104977f000000000000000000000000000000000000000000000000000000000000000081565b6040516102549190614e5b565b3480156104b057600080fd5b506104b96114fd565b6040516102549190614e6f565b3480156104d257600080fd5b506101fb6104e1366004614ec3565b611562565b3480156104f257600080fd5b506000546001600160a01b0316610497565b34801561051057600080fd5b506101fb61051f366004614f1d565b6115d6565b34801561053057600080fd5b506101fb61053f366004614f3a565b611640565b34801561055057600080fd5b5061024a61055f366004614f65565b61167c565b34801561057057600080fd5b5061024a61179d565b34801561058557600080fd5b506101fb610594366004615019565b6119e3565b3480156105a557600080fd5b506105b96105b4366004615068565b611bce565b60405161025491906150f2565b3480156105d257600080fd5b506101fb6105e1366004614b11565b611dd2565b3480156105f257600080fd5b506004546005546106629160ff80821692610100830482169262010000810483169263010000008204811692600160201b83049091169163ffffffff600160281b8204811692600160481b8304821692600160681b8104831692600160881b90910416906001600160601b03168a565b604080519a15158b5298151560208b01529615159789019790975260ff948516606089015292909316608087015263ffffffff90811660a087015291821660c0860152811660e08501529091166101008301526001600160601b031661012082015261014001610254565b3480156106d957600080fd5b50600a54610497906001600160a01b031681565b3480156106f957600080fd5b506101fb610708366004614ae1565b611f03565b34801561071957600080fd5b506101fb610728366004615105565b6120bf565b34801561073957600080fd5b506101fb610748366004614ae1565b6125ac565b34801561075957600080fd5b5061024a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561078d57600080fd5b506101fb61079c366004615159565b612899565b3480156107ad57600080fd5b506101fb6107bc366004614ae1565b6128b2565b61024a6107cf36600461519a565b6129c3565b3480156107e057600080fd5b506107f46107ef366004614b11565b612c21565b6040516102549493929190615272565b34801561081057600080fd5b50600b5461082c9063ffffffff80821691600160201b90041682565b6040805163ffffffff938416815292909116602083015201610254565b34801561085557600080fd5b506101fb610864366004614abd565b612d0e565b34801561087557600080fd5b506101fb6108843660046152be565b612d1f565b34801561089557600080fd5b5061024a6108a43660046152ea565b612e88565b6108b1612f9f565b60095460005b81811015610a3657826001600160a01b0316600982815481106108dc576108dc615330565b6000918252602090912001546001600160a01b031603610a2457600961090360018461535c565b8154811061091357610913615330565b600091825260209091200154600980546001600160a01b03909216918390811061093f5761093f615330565b600091825260209091200180546001600160a01b0319166001600160a01b039290921691909117905582600961097660018561535c565b8154811061098657610986615330565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060098054806109c5576109c561536f565b600082815260209020810160001990810180546001600160a01b03191690550190556040517ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3790610a17908590614e5b565b60405180910390a1505050565b80610a2e81615385565b9150506108b7565b5081604051635428d44960e01b8152600401610a529190614e5b565b60405180910390fd5b50565b60008281526007602052604090205482906001600160a01b031680610a995760405163c5171ee960e01b815260048101839052602401610a52565b336001600160a01b03821614610ac45780604051636c51fda960e11b8152600401610a529190614e5b565b600454610100900460ff1615610aed5760405163769dd35360e11b815260040160405180910390fd5b600084815260086020526040902054600160601b90046001600160401b031615610b2a57604051631685ecdd60e31b815260040160405180910390fd5b6000848152600860209081526040918290208251808401909352546001600160601b038116808452600160601b9091046001600160401b031691830191909152610b7386612ff4565b600280546001600160601b03169082906000610b8f838561539e565b92506101000a8154816001600160601b0302191690836001600160601b031602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb87846001600160601b03166040518363ffffffff1660e01b8152600401610c0a9291906153c5565b6020604051808303816000875af1158015610c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4d91906153de565b610c7d5760405163cf47918160e01b81526001600160601b03808316600483015283166024820152604401610a52565b867f3784f77e8e883de95b5d47cd713ced01229fa74d118c0a462224bcb0516d43f18784604051610caf9291906153fb565b60405180910390a250505050505050565b610cc8612f9f565b600a546001600160a01b031615610cff57600a5460405163ea6d390560e01b8152610a52916001600160a01b031690600401614e5b565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b610d29612f9f565b6064610d3b60a0830160808401615437565b60ff161180610d555750610d556040820160208301614f1d565b80610d6b5750610d6b6060820160408301614f1d565b15610d895760405163b0e7bd8360e01b815260040160405180910390fd5b806004610d96828261549d565b9050507e28d3a46e95e67def989d41c66eb331add9809460b95b5fb4eb006157728fc581604051610dc79190615670565b60405180910390a150565b60045460009062010000900460ff1615610dff5760405163ab35696f60e01b815260040160405180910390fd5b600454610100900460ff1615610e285760405163769dd35360e11b815260040160405180910390fd5b3415610e4957604051630b829bad60e21b8152346004820152602401610a52565b6000806000610e5a88338989613143565b925092509250600080610e6d338b61328e565b600087815260106020908152604091829020885181548a8401518b8601516060808e015163ffffffff90951666ffffffffffffff1990941693909317600160201b62ffffff9384160217600160381b600160e81b031916600160381b61ffff92831602600160481b600160e81b03191617600160481b6001600160a01b03909516949094029390931790935584513381526001600160401b038b1694810194909452918e169383019390935281018e9052908c16608082015260a081018390526001600160601b03821660c0820152919350915085907fb7933fba96b6b452eb44f99fdc08052a45dff82363d59abaff0456931c3d24599060e00160405180910390a2509298975050505050505050565b610f86612f9f565b610f8f8161346a565b15610faf578060405163ac8a27ef60e01b8152600401610a529190614e5b565b600980546001810182556000919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590610dc7908390614e5b565b600a546001600160a01b0316331461105557604051634bea32db60e11b815260040160405180910390fd5b828015806110635750601f81115b1561108457604051634ecc4fef60e01b815260048101829052602401610a52565b8082146110a85760405163339f8a9d60e01b8152610a529082908490600401615758565b60005b8181101561110d576110fb8686838181106110c8576110c8615330565b90506020020160208101906110dd9190614abd565b8585848181106110ef576110ef615330565b90506020020135612d1f565b8061110581615385565b9150506110ab565b505050505050565b600a546000906001600160a01b0316331461114357604051634bea32db60e11b815260040160405180910390fd5b60045462010000900460ff161561116d5760405163ab35696f60e01b815260040160405180910390fd5b6001600160c01b038416156111aa57600680546001600160601b038616600160a01b02600160201b600160a01b0390911663ffffffff4216171790555b6001600160401b038316156111ff5760068054436001600160401b03908116600160201b02600160201b600160601b0319918716600160601b0291909116600160201b600160a01b0319909216919091171790555b600080866001600160401b0381111561121a5761121a614b68565b60405190808252806020026020018201604052801561125357816020015b6112406148f6565b8152602001906001900390816112385790505b50905060005b8781101561135557600089898381811061127557611275615330565b90506020028101906112879190615766565b611290906158ea565b9050600061129f82888b6134d3565b905085806112aa5750805b604083015151519096501515806112c957506040820151516020015115155b15611340576040805160808101825283516001600160401b0316815260208085015162ffffff168183015284830180515151938301939093529151519091015160608201528451859061ffff881690811061132657611326615330565b6020026020010181905250848061133c906159d0565b9550505b5050808061134d90615385565b915050611259565b5060008261ffff166001600160401b0381111561137457611374614b68565b6040519080825280602002602001820160405280156113ad57816020015b61139a6148f6565b8152602001906001900390816113925790505b50905060005b8361ffff16811015611409578281815181106113d1576113d1615330565b60200260200101518282815181106113eb576113eb615330565b6020026020010181905250808061140190615385565b9150506113b3565b507ff10ea936d00579b4c52035ee33bf46929646b3aa87554c565d8fb2c7aa549c448588888460405161143f94939291906159f1565b60405180910390a150505095945050505050565b6001546001600160a01b031633146114a65760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610a52565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61150561492c565b6040805161010081019182905290600f90600890826000855b82829054906101000a900462ffffff1662ffffff168152602001906003019060208260020104928301926001038202915080841161151e5790505050505050905090565b61156a612f9f565b8051600b80546020808501805163ffffffff908116600160201b026001600160401b031990941695811695861793909317909355604080519485529251909116908301527f0cc54509a45ab33cd67614d4a2892c083ecf8fb43b9d29f6ea8130b9023e51df9101610dc7565b6115de612f9f565b60045460ff6201000090910416151581151514610a5b5760048054821515620100000262ff0000199091161790556040517f49ba7c1de2d8853088b6270e43df2118516b217f38b917dd2b80dea360860fbe90610dc790831515815260200190565b600a546001600160a01b0316331461166b57604051634bea32db60e11b815260040160405180910390fd5b611678600f82600861494b565b5050565b604080516101408101825260045460ff80821615158352610100808304821615156020808601919091526201000084048316151585870152630100000084048316606080870191909152600160201b808604909416608080880191909152600160281b860463ffffffff90811660a0890152600160481b8704811660c0890152600160681b8704811660e0890152600160881b9096048616938701939093526005546001600160601b039081166101208801528751938401885260065480871685526001600160401b03958104861693850193909352600160601b830490941696830196909652600160a01b90049091169381019390935260009283926117889288169187919061366b565b50506001600160601b03169695505050505050565b600454600090610100900460ff16156117c95760405163769dd35360e11b815260040160405180910390fd5b60045462010000900460ff16156117f35760405163ab35696f60e01b815260040160405180910390fd5b60003361180160014361535c565b6001546040516001600160601b0319606094851b81166020830152924060348201523090931b90911660548301526001600160c01b0319600160a01b90910460c01b16606882015260700160408051808303601f19018152919052805160209091012060018054919250600160a01b9091046001600160401b031690601461188883615a86565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b038111156118c7576118c7614b68565b6040519080825280602002602001820160405280156118f0578160200160208202803683370190505b5060408051808201825260008082526020808301828152878352600882528483209351845491516001600160601b039091166001600160a01b031992831617600160601b6001600160401b039092169190910217909355835160608101855233815280820183815281860187815289855260078452959093208151815486166001600160a01b03918216178255935160018201805490961694169390931790935592518051949550919390926119ad9260028501929101906149e9565b505060405133915083907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d90600090a350905090565b600454610100900460ff1615611a0c5760405163769dd35360e11b815260040160405180910390fd5b60045462010000900460ff1615611a365760405163ab35696f60e01b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611a7f576040516344b0e3c360e01b815260040160405180910390fd5b60208114611aa557604051636865567560e01b8152610a52906020908390600401615aaa565b6000611ab382840184614b11565b6000818152600760205260409020549091506001600160a01b0316611aee5760405163c5171ee960e01b815260048101829052602401610a52565b600081815260086020526040812080546001600160601b031691869190611b158385615abe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600260008282829054906101000a90046001600160601b0316611b5d9190615abe565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a828784611bb09190615ade565b604051611bbe929190615758565b60405180910390a2505050505050565b600454606090610100900460ff1615611bfa5760405163769dd35360e11b815260040160405180910390fd5b60008381526010602081815260408084208151608081018352815463ffffffff8116825262ffffff600160201b8204168286015261ffff600160381b820416938201939093526001600160a01b03600160481b8404811660608301908152968a9052949093526001600160e81b031990911690559151163314611c9857806060015133604051638e30e82360e01b8152600401610a52929190615af1565b8051600090611cce907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff16615b0b565b90506000611cda613715565b90506000836020015162ffffff1682611cf3919061535c565b9050808310611d385782846020015162ffffff1684611d129190615ade565b611d1d906001615ade565b6040516315ad27c360e01b8152600401610a52929190615758565b6001600160401b03831115611d63576040516302c6ef8160e11b815260048101849052602401610a52565b604051888152339088907f16f3f633197fafab10a5df69e6f3f2f7f20092f08d8d47de0a91c0f4b96a1a259060200160405180910390a3611dc68785600d6000611db1888a6020015161379f565b815260200190815260200160002054866137ae565b98975050505050505050565b600454610100900460ff1615611dfb5760405163769dd35360e11b815260040160405180910390fd5b6000818152600760205260409020546001600160a01b0316611e335760405163c5171ee960e01b815260048101829052602401610a52565b6000818152600760205260409020600101546001600160a01b03163314611e8a576000818152600760205260409081902060010154905163d084e97560e01b8152610a52916001600160a01b031690600401614e5b565b6000818152600760205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ef7918591615af1565b60405180910390a25050565b60008281526007602052604090205482906001600160a01b031680611f3e5760405163c5171ee960e01b815260048101839052602401610a52565b336001600160a01b03821614611f695780604051636c51fda960e11b8152600401610a529190614e5b565b600454610100900460ff1615611f925760405163769dd35360e11b815260040160405180910390fd5b60045462010000900460ff1615611fbc5760405163ab35696f60e01b815260040160405180910390fd5b60008481526007602052604090206002015460631901611fef576040516305a48e0f60e01b815260040160405180910390fd5b60036000611ffd8587613967565b815260208101919091526040016000205460ff166120b9576001600360006120258688613967565b815260208082019290925260409081016000908120805460ff191694151594909417909355868352600782528083206002018054600181018255908452919092200180546001600160a01b0319166001600160a01b0386161790555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1906120b0908690614e5b565b60405180910390a25b50505050565b600454610100900460ff16156120e85760405163769dd35360e11b815260040160405180910390fd5b6120f18361346a565b6121105782604051635428d44960e01b8152600401610a529190614e5b565b604081146121355760408051636865567560e01b8152610a5291908390600401615aaa565b600061214382840184615b22565b90506000806000806121588560200151612c21565b9350935093509350816001600160a01b0316336001600160a01b0316146121945781604051636c51fda960e11b8152600401610a529190614e5b565b876001600160a01b031663294daa496040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f69190615b5c565b60ff16856000015160ff1614612293578460000151886001600160a01b031663294daa496040518163ffffffff1660e01b8152600401602060405180830381865afa158015612249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226d9190615b5c565b60405163e7aada9560e01b815260ff928316600482015291166024820152604401610a52565b6001600160401b038316156122bb57604051631685ecdd60e31b815260040160405180910390fd5b60006040518060a001604052806122d0600190565b60ff16815260200187602001518152602001846001600160a01b03168152602001838152602001866001600160601b031681525090506000816040516020016123199190615b79565b60405160208183030381529060405290506123378760200151612ff4565b600280548791906000906123559084906001600160601b031661539e565b92506101000a8154816001600160601b0302191690836001600160601b031602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb8b886040518363ffffffff1660e01b81526004016123c79291906153fb565b6020604051808303816000875af11580156123e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061240a91906153de565b61244b5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610a52565b60405163ce3f471960e01b81526001600160a01b038b169063ce3f471990612477908490600401615c25565b600060405180830381600087803b15801561249157600080fd5b505af11580156124a5573d6000803e3d6000fd5b50506004805461ff00191661010017905550600090505b835181101561254f578381815181106124d7576124d7615330565b60200260200101516001600160a01b0316638ea981178c6040518263ffffffff1660e01b815260040161250a9190614e5b565b600060405180830381600087803b15801561252457600080fd5b505af1158015612538573d6000803e3d6000fd5b50505050808061254790615385565b9150506124bc565b506004805461ff00191690556020870151875160405160ff909116907fbd89b747474d3fc04664dfbd1d56ae7ffbe46ee097cdb9979c13916bb76269ce90612598908e90614e5b565b60405180910390a350505050505050505050565b60008281526007602052604090205482906001600160a01b0316806125e75760405163c5171ee960e01b815260048101839052602401610a52565b336001600160a01b038216146126125780604051636c51fda960e11b8152600401610a529190614e5b565b600454610100900460ff161561263b5760405163769dd35360e11b815260040160405180910390fd5b600084815260086020526040902054600160601b90046001600160401b03161561267857604051631685ecdd60e31b815260040160405180910390fd5b600360006126868587613967565b815260208101919091526040016000205460ff166126bb5783836040516379bfd40160e01b8152600401610a52929190615c38565b60008481526007602090815260408083206002018054825181850281018501909352808352919290919083018282801561271e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612700575b50505050509050600060018251612735919061535c565b905060005b825181101561284057856001600160a01b031683828151811061275f5761275f615330565b60200260200101516001600160a01b03160361282e57600083838151811061278957612789615330565b6020026020010151905080600760008a815260200190815260200160002060020183815481106127bb576127bb615330565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558981526007909152604090206002018054806128065761280661536f565b600082815260209020810160001990810180546001600160a01b031916905501905550612840565b8061283881615385565b91505061273a565b506003600061284f8789613967565b815260208101919091526040908101600020805460ff191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a790611bbe908890614e5b565b604051632cb6686f60e01b815260040160405180910390fd5b60008281526007602052604090205482906001600160a01b0316806128ed5760405163c5171ee960e01b815260048101839052602401610a52565b336001600160a01b038216146129185780604051636c51fda960e11b8152600401610a529190614e5b565b600454610100900460ff16156129415760405163769dd35360e11b815260040160405180910390fd5b6000848152600760205260409020600101546001600160a01b038481169116146120b9576000848152600760205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a1906120b09033908790615af1565b60045460009062010000900460ff16156129f05760405163ab35696f60e01b815260040160405180910390fd5b600454610100900460ff1615612a195760405163769dd35360e11b815260040160405180910390fd5b3415612a3a57604051630b829bad60e21b8152346004820152602401610a52565b600080612a4989338a8a613143565b925050915060006040518061010001604052808481526020018a61ffff168152602001336001600160a01b031681526020018781526020018863ffffffff166001600160601b031681526020018b81526020016000815260200160008152509050600080612ab68361397d565b60c087019190915260e08601919091526040519193509150612ae29085908c908f908790602001615c4f565b60405160208183030381529060405280519060200120600c6000878152602001908152602001600020819055506000604051806101600160405280878152602001336001600160a01b03168152602001866001600160401b031681526020018c62ffffff1681526020018e81526020018d61ffff1681526020018b63ffffffff1681526020018581526020018a8152602001848152602001836001600160601b0316815250905080600001517f01872fb9c7d6d68af06a17347935e04412da302a377224c205e672c26e18c37f82602001518360400151846060015185608001518660a001518760c001518860e0015160c001518960e0015160e001518a61010001518b61012001518c6101400151604051612c089b9a99989796959493929190615d02565b60405180910390a250939b9a5050505050505050505050565b600081815260076020526040812054819081906060906001600160a01b0316612c605760405163c5171ee960e01b815260048101869052602401610a52565b60008581526008602090815260408083205460078352928190208054600290910180548351818602810186019094528084526001600160601b03861695600160601b90046001600160401b0316946001600160a01b03909316939192839190830182828015612cf857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612cda575b5050505050905093509350935093509193509193565b612d16612f9f565b610a5b81613bb4565b600a546001600160a01b03163314612d4a57604051634bea32db60e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90612d9890859085906004016153c5565b6020604051808303816000875af1158015612db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddb91906153de565b611678576040516370a0823160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190612e2b903090600401614e5b565b602060405180830381865afa158015612e48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6c9190615d98565b8160405163cf47918160e01b8152600401610a52929190615758565b604080516101408101825260045460ff80821615158352610100808304821615156020808601919091526201000084048316151585870152630100000084048316606080870191909152600160201b80860490941660808088019190915263ffffffff600160281b8704811660a0890152600160481b8704811660c0890152600160681b8704811660e0890152600160881b9096048616938701939093526005546001600160601b039081166101208801528751938401885260065495861684526001600160401b03948604851692840192909252600160601b850490931695820195909552600160a01b90920490931692810192909252600091612f8d9190613c57565b6001600160601b031690505b92915050565b6000546001600160a01b03163314612ff25760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610a52565b565b6000818152600760209081526040808320815160608101835281546001600160a01b0390811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561307a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161305c575b505050505081525050905060005b8160400151518110156130ea57600360006130c0846040015184815181106130b2576130b2615330565b602002602001015186613967565b81526020810191909152604001600020805460ff19169055806130e281615385565b915050613088565b50600082815260076020526040812080546001600160a01b031990811682556001820180549091169055906131226002830182614a3e565b505050600090815260086020526040902080546001600160a01b0319169055565b600061314d614a5c565b60006103e88561ffff16111561317c57846103e8604051634a90778560e01b8152600401610a52929190615aaa565b8461ffff166000036131a1576040516308fad2a760e01b815260040160405180910390fd5b6000806131ac613c9d565b600e54919350915065ffffffffffff1660006132178b8b84604080513060208201529081018490526001600160a01b038316606082015265ffffffffffff8216608082015260009060a00160408051601f198184030181529190528051602090910120949350505050565b9050613224826001615db1565b600e805465ffffffffffff9290921665ffffffffffff199092169190911790556040805160808101825263ffffffff909416845262ffffff8916602085015261ffff8a16908401526001600160a01b038a1660608401529550909350909150509450945094915050565b604080516080808201835260065463ffffffff8082168452600160201b8083046001600160401b03908116602080880191909152600160601b850490911686880152600160a01b9093046001600160601b0390811660608088019190915287516101408101895260045460ff808216151583526101008083048216151598840198909852620100008204811615159a83019a909a52630100000081048a169282019290925292810490971694820194909452600160281b8604821660a0820152600160481b8604821660c0820152600160681b8604821660e0820152600160881b9095041690840152600554166101208301526000918291906003836133948888613967565b815260208101919091526040016000205460ff166133c95784866040516379bfd40160e01b8152600401610a52929190615c38565b60006133d58284613c57565b600087815260086020526040902080546001600160601b0392831693509091168281101561342457815460405163cf47918160e01b8152610a52916001600160601b0316908590600401615dd0565b81546001600160601b0319908116918490036001600160601b038181169390931790935560028054918216918316859003909216179055909450925050505b9250929050565b6000805b6009548110156134ca57826001600160a01b03166009828154811061349557613495615330565b6000918252602090912001546001600160a01b0316036134b85750600192915050565b806134c281615385565b91505061346e565b50600092915050565b6000826001600160401b031684600001516001600160401b0316111561352257835160405163012d824d60e01b81526001600160401b0380861660048301529091166024820152604401610a52565b606084015151604080860151905160009161353f91602001615de9565b60405160208183030381529060405280519060200120905085604001516000015160006002811061357257613572615330565b602002015115801561358b575060408601515160200151155b156135c557600d60006135af88600001516001600160401b0316896020015161379f565b8152602001908152602001600020549050613648565b856080015115613648576000600d60006135f089600001516001600160401b03168a6020015161379f565b81526020810191909152604001600020549050806136425781600d60006136288a600001516001600160401b03168b6020015161379f565b815260208101919091526040016000205560019350613646565b8091505b505b6000613655838389613d70565b905083806136605750805b979650505050505050565b60008060008061367b8686614189565b6001600160401b031690506000613693826010615b0b565b9050600060146136a4836015615b0b565b6136ae9190615e29565b89516136ba9190615b0b565b838960e0015163ffffffff168c6136d19190615abe565b6001600160601b03166136e49190615b0b565b6136ee9190615ade565b90506000806137008360008c8c614202565b909d909c50949a509398505050505050505050565b60004661a4b181148061372a575062066eed81145b156137985760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561376e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137929190615d98565b91505090565b4391505090565b62ffffff1660189190911b1790565b6060826137e05760405163220a34e960e11b8152600481018690526001600160401b0383166024820152604401610a52565b604080516020808201889052865163ffffffff168284015286015162ffffff166060808301919091529186015161ffff166080820152908501516001600160a01b031660a082015260c0810184905260009060e0016040516020818303038152906040528051906020012090506103e8856040015161ffff1611156138825784604001516103e8604051634a90778560e01b8152600401610a52929190615aaa565b6000856040015161ffff166001600160401b038111156138a4576138a4614b68565b6040519080825280602002602001820160405280156138cd578160200160208202803683370190505b50905060005b866040015161ffff168161ffff16101561395c57828160405160200161391092919091825260f01b6001600160f01b031916602082015260220190565b6040516020818303038152906040528051906020012060001c828261ffff168151811061393f5761393f615330565b602090810291909101015280613954816159d0565b9150506138d3565b509695505050505050565b60a081901b6001600160a01b0383161792915050565b6000806000806003600061399987604001518860a00151613967565b815260208101919091526040016000205460ff166139d6578460a0015185604001516040516379bfd40160e01b8152600401610a52929190615c38565b604080516080808201835260065463ffffffff80821684526001600160401b03600160201b8084048216602080880191909152600160601b8504909216868801526001600160601b03600160a01b909404841660608088019190915287516101408101895260045460ff808216151583526101008083048216151596840196909652620100008204811615159a83019a909a52630100000081048a168284015292830490981688870152600160281b8204841660a0890152600160481b8204841660c0890152600160681b8204841660e0890152600160881b90910490921690860152600554909116610120850152908801519088015191929160009182918291613ae291868861366b565b60a08d0151600090815260086020526040902080546001600160601b0394851697509295509093509116841115613b3a57805460405163cf47918160e01b8152610a52916001600160601b0316908690600401615dd0565b80546001600160601b0360016001600160401b03600160601b8085048216929092011602818116828416178790038083166001600160601b03199283166001600160a01b03199095169490941793909317909355600280548083168890039092169190931617909155929a91995097509095509350505050565b336001600160a01b03821603613c065760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610a52565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080613c648484614189565b8460c0015163ffffffff16613c799190615e3d565b6001600160401b031690506000613c938260008787614202565b5095945050505050565b6000806000613caa613715565b90506000613cd87f000000000000000000000000000000000000000000000000000000000000000083615e60565b9050600081613d077f000000000000000000000000000000000000000000000000000000000000000085615ade565b613d11919061535c565b90506000613d3f7f000000000000000000000000000000000000000000000000000000000000000083615e29565b905063ffffffff8110613d65576040516307b2a52360e41b815260040160405180910390fd5b909590945092505050565b6000806040518060c00160405280866001600160401b03811115613d9657613d96614b68565b604051908082528060200260200182016040528015613dbf578160200160208202803683370190505b508152602001866001600160401b03811115613ddd57613ddd614b68565b6040519080825280601f01601f191660200182016040528015613e07576020820181803683370190505b508152602001866001600160401b03811115613e2557613e25614b68565b604051908082528060200260200182016040528015613e5857816020015b6060815260200190600190039081613e435790505b50815260006020820152604001866001600160401b03811115613e7d57613e7d614b68565b604051908082528060200260200182016040528015613ea6578160200160208202803683370190505b508152602001866001600160401b03811115613ec457613ec4614b68565b604051908082528060200260200182016040528015613eed578160200160208202803683370190505b509052905060005b8581101561406c57600084606001518281518110613f1557613f15615330565b60200260200101519050600080600080613f3989600001518a602001518c8861424d565b93509350935093508315613f8d57828760400151886060015161ffff1681518110613f6657613f66615330565b602090810291909101015260608701805190613f81826159d0565b61ffff16905250613fc0565b600160f81b87602001518781518110613fa857613fa8615330565b60200101906001600160f81b031916908160001a9053505b8780613fca575080155b85515188518051929a50909188908110613fe657613fe6615330565b602002602001018181525050818760800151878151811061400957614009615330565b60200260200101906001600160601b031690816001600160601b031681525050846000015160a001518760a00151878151811061404857614048615330565b6020026020010181815250505050505050808061406490615385565b915050613ef5565b5060608301515115614181576000816060015161ffff166001600160401b0381111561409a5761409a614b68565b6040519080825280602002602001820160405280156140cd57816020015b60608152602001906001900390816140b85790505b50905060005b826060015161ffff1681101561413157826040015181815181106140f9576140f9615330565b602002602001015182828151811061411357614113615330565b6020026020010181905250808061412990615385565b9150506140d3565b5081516020830151608084015160a08501516040517f8f79f730779e875ce76c428039cc2052b5b5918c2a55c598fab251c1198aec549461417794909390928792615ead565b60405180910390a1505b509392505050565b815160009080156141a6575060408201516001600160401b031615155b156141fa5761010083015163ffffffff16431080806141e757506101008401516141d69063ffffffff164361535c565b83602001516001600160401b031610155b156141f85750506040810151612f99565b505b503a92915050565b600080600060648560600151606461421a9190615f50565b6142279060ff1689615b0b565b6142319190615e29565b905061423f818787876145bc565b925092505094509492505050565b805160a09081015160009081526008602090815260408083208551948501519151939460609486948594859261428b928e928e929091879101615c4f565b60408051601f19818403018152918152815160209283012084516000908152600c90935291205490915081146142fe5750505460408051808201909152601081526f756e6b6e6f776e2063616c6c6261636b60801b60208201526001955093506001600160601b031691508390506145b1565b50614307614a5c565b600061433c7f00000000000000000000000000000000000000000000000000000000000000006001600160401b038e16615e29565b6040805160808101825263ffffffff909216825262ffffff8d1660208084019190915285015161ffff16828201528401516001600160a01b0316606082015291508990506143d0575050604080518082019091526016815275756e617661696c61626c652072616e646f6d6e65737360501b60208201529054600195509093506001600160601b03169150600090506145b1565b60006143e28360000151838c8f6137ae565b606080840151855191860151604051939450909260009263d21ea8fd60e01b9261441192879190602401615f69565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526004805461ff00191661010017905590506000805a9050600061447c8e60000151608001516001600160601b0316896040015186614630565b9093509050806144b1578d516080015160405163aad1598360e01b8152610a52916001600160601b0316908490600401615758565b506000610bb85a6144c29190615ade565b6004805461ff00191690559050818110156144eb576144eb6144e4828461535c565b8f5161466f565b8854600160601b90046001600160401b031689600c61450983615f94565b82546001600160401b039182166101009390930a92830291909202199091161790555087516000908152600c60205260408120558261457f5760408051808201909152601081526f195e1958dd5d1a5bdb8819985a5b195960821b60208201528954600191906001600160601b0316600061459f565b604080516020810190915260008082528a549091906001600160601b0316825b9c509c509c509c505050505050505050505b945094509450949050565b6000808085156145cc57856145d6565b6145d6858561489b565b90506000816145ed89670de0b6b3a7640000615b0b565b6145f79190615e29565b9050676765c793fa10079d601b1b8111156146245760405162de437160e81b815260040160405180910390fd5b97909650945050505050565b6000805a610bb8811061466657610bb881039050856040820482031115614666576000808551602087016000898bf19250600191505b50935093915050565b80608001516001600160601b0316821115614688575050565b6004546000906064906146a590600160201b900460ff1682615fb7565b60ff168360c001518585608001516001600160601b03166146c6919061535c565b6146d09190615b0b565b6146da9190615b0b565b6146e49190615e29565b60e080840151604080516101408101825260045460ff80821615158352610100808304821615156020808601919091526201000084048316151585870152630100000084048316606080870191909152600160201b80860490941660808088019190915263ffffffff600160281b8704811660a0890152600160481b8704811660c0890152600160681b870481169a88019a909a52600160881b9095048916928601929092526005546001600160601b039081166101208701528651948501875260065498891685526001600160401b03938904841691850191909152600160601b880490921694830194909452600160a01b909504909416918401919091529293506000926147f792859291906145bc565b5060a08401516000908152600860205260408120805492935083929091906148299084906001600160601b0316615abe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600260008282829054906101000a90046001600160601b03166148719190615abe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050505050565b60a0820151606082015160009190600163ffffffff831611908180156148d7575084516148ce9063ffffffff164261535c565b8363ffffffff16105b156148e457506101208501515b6001600160601b031695945050505050565b604051806080016040528060006001600160401b03168152602001600062ffffff16815260200160008152602001600081525090565b6040518061010001604052806008906020820280368337509192915050565b6001830191839082156149d95791602002820160005b838211156149a857833562ffffff1683826101000a81548162ffffff021916908362ffffff1602179055509260200192600301602081600201049283019260010302614961565b80156149d75782816101000a81549062ffffff02191690556003016020816002010492830192600103026149a8565b505b506149e5929150614a83565b5090565b8280548282559060005260206000209081019282156149d9579160200282015b828111156149d957825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614a09565b5080546000825590600052602060002090810190610a5b9190614a83565b60408051608081018252600080825260208201819052918101829052606081019190915290565b5b808211156149e55760008155600101614a84565b6001600160a01b0381168114610a5b57600080fd5b8035614ab881614a98565b919050565b600060208284031215614acf57600080fd5b8135614ada81614a98565b9392505050565b60008060408385031215614af457600080fd5b823591506020830135614b0681614a98565b809150509250929050565b600060208284031215614b2357600080fd5b5035919050565b60006101408284031215614b3d57600080fd5b50919050565b803561ffff81168114614ab857600080fd5b803562ffffff81168114614ab857600080fd5b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614ba057614ba0614b68565b60405290565b60405161010081016001600160401b0381118282101715614ba057614ba0614b68565b60405160a081016001600160401b0381118282101715614ba057614ba0614b68565b604051602081016001600160401b0381118282101715614ba057614ba0614b68565b604051601f8201601f191681016001600160401b0381118282101715614c3557614c35614b68565b604052919050565b600082601f830112614c4e57600080fd5b81356001600160401b03811115614c6757614c67614b68565b614c7a601f8201601f1916602001614c0d565b818152846020838601011115614c8f57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215614cc257600080fd5b84359350614cd260208601614b43565b9250614ce060408601614b55565b915060608501356001600160401b03811115614cfb57600080fd5b614d0787828801614c3d565b91505092959194509250565b60008083601f840112614d2557600080fd5b5081356001600160401b03811115614d3c57600080fd5b6020830191508360208260051b850101111561346357600080fd5b60008060008060408587031215614d6d57600080fd5b84356001600160401b0380821115614d8457600080fd5b614d9088838901614d13565b90965094506020870135915080821115614da957600080fd5b50614db687828801614d13565b95989497509550505050565b80356001600160401b0381168114614ab857600080fd5b600080600080600060808688031215614df157600080fd5b85356001600160401b03811115614e0757600080fd5b614e1388828901614d13565b90965094505060208601356001600160c01b0381168114614e3357600080fd5b9250614e4160408701614dc2565b9150614e4f60608701614dc2565b90509295509295909350565b6001600160a01b0391909116815260200190565b6101008101818360005b6008811015614e9d57815162ffffff16835260209283019290910190600101614e79565b50505092915050565b63ffffffff81168114610a5b57600080fd5b8035614ab881614ea6565b600060408284031215614ed557600080fd5b614edd614b7e565b8235614ee881614ea6565b81526020830135614ef881614ea6565b60208201529392505050565b8015158114610a5b57600080fd5b8035614ab881614f04565b600060208284031215614f2f57600080fd5b8135614ada81614f04565b6000610100808385031215614f4e57600080fd5b838184011115614f5d57600080fd5b509092915050565b60008060008060808587031215614f7b57600080fd5b843593506020850135614f8d81614ea6565b925060408501356001600160401b0380821115614fa957600080fd5b614fb588838901614c3d565b93506060870135915080821115614fcb57600080fd5b50614d0787828801614c3d565b60008083601f840112614fea57600080fd5b5081356001600160401b0381111561500157600080fd5b60208301915083602082850101111561346357600080fd5b6000806000806060858703121561502f57600080fd5b843561503a81614a98565b93506020850135925060408501356001600160401b0381111561505c57600080fd5b614db687828801614fd8565b60008060006060848603121561507d57600080fd5b833592506020840135915060408401356001600160401b038111156150a157600080fd5b6150ad86828701614c3d565b9150509250925092565b600081518084526020808501945080840160005b838110156150e7578151875295820195908201906001016150cb565b509495945050505050565b602081526000614ada60208301846150b7565b60008060006040848603121561511a57600080fd5b833561512581614a98565b925060208401356001600160401b0381111561514057600080fd5b61514c86828701614fd8565b9497909650939450505050565b6000806020838503121561516c57600080fd5b82356001600160401b0381111561518257600080fd5b61518e85828601614fd8565b90969095509350505050565b60008060008060008060c087890312156151b357600080fd5b863595506151c360208801614b43565b94506151d160408801614b55565b935060608701356151e181614ea6565b925060808701356001600160401b03808211156151fd57600080fd5b6152098a838b01614c3d565b935060a089013591508082111561521f57600080fd5b5061522c89828a01614c3d565b9150509295509295509295565b600081518084526020808501945080840160005b838110156150e75781516001600160a01b03168752958201959082019060010161524d565b6001600160601b03851681526001600160401b03841660208201526001600160a01b03831660408201526080606082018190526000906152b490830184615239565b9695505050505050565b600080604083850312156152d157600080fd5b82356152dc81614a98565b946020939093013593505050565b600080604083850312156152fd57600080fd5b8235915060208301356001600160401b0381111561531a57600080fd5b61532685828601614c3d565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115612f9957612f99615346565b634e487b7160e01b600052603160045260246000fd5b60006001820161539757615397615346565b5060010190565b6001600160601b038281168282160390808211156153be576153be615346565b5092915050565b6001600160a01b03929092168252602082015260400190565b6000602082840312156153f057600080fd5b8151614ada81614f04565b6001600160a01b039290921682526001600160601b0316602082015260400190565b60ff81168114610a5b57600080fd5b8035614ab88161541d565b60006020828403121561544957600080fd5b8135614ada8161541d565b60008135612f9981614f04565b60008135612f998161541d565b60008135612f9981614ea6565b6001600160601b0381168114610a5b57600080fd5b60008135612f998161547b565b81356154a881614f04565b815490151560ff1660ff19919091161781556154e36154c960208401615454565b82805461ff00191691151560081b61ff0016919091179055565b61550e6154f260408401615454565b82805462ff0000191691151560101b62ff000016919091179055565b61553761551d60608401615461565b825463ff000000191660189190911b63ff00000016178255565b61556461554660808401615461565b82805460ff60201b191660209290921b60ff60201b16919091179055565b61559761557360a0840161546e565b82805463ffffffff60281b191660289290921b63ffffffff60281b16919091179055565b6155ca6155a660c0840161546e565b82805463ffffffff60481b191660489290921b63ffffffff60481b16919091179055565b6155fd6155d960e0840161546e565b82805463ffffffff60681b191660689290921b63ffffffff60681b16919091179055565b61563161560d610100840161546e565b82805463ffffffff60881b191660889290921b63ffffffff60881b16919091179055565b6116786156416101208401615490565b6001830180546001600160601b0319166001600160601b0392909216919091179055565b8035614ab88161547b565b61014081016156888261568285614f12565b15159052565b61569460208401614f12565b151560208301526156a760408401614f12565b151560408301526156ba6060840161542c565b60ff1660608301526156ce6080840161542c565b60ff1660808301526156e260a08401614eb8565b63ffffffff1660a08301526156f960c08401614eb8565b63ffffffff1660c083015261571060e08401614eb8565b63ffffffff1660e0830152610100615729848201614eb8565b63ffffffff1690830152610120615741848201615665565b6001600160601b038116848301525b505092915050565b918252602082015260400190565b6000823560be1983360301811261577c57600080fd5b9190910192915050565b600082601f83011261579757600080fd5b813560206001600160401b03808311156157b3576157b3614b68565b8260051b6157c2838201614c0d565b93845285810183019383810190888611156157dc57600080fd5b84880192505b85831015611dc6578235848111156157f957600080fd5b8801601f196040828c038201121561581057600080fd5b615818614b7e565b878301358781111561582957600080fd5b8301610100818e038401121561583e57600080fd5b615846614ba6565b925088810135835261585a60408201614b43565b8984015261586a60608201614aad565b604084015260808101358881111561588157600080fd5b61588f8e8b83850101614c3d565b6060850152506158a160a08201615665565b608084015260c081013560a084015260e081013560c084015261010081013560e0840152508181526158d560408401615665565b818901528452505091840191908401906157e2565b600081360360c08112156158fd57600080fd5b615905614bc9565b61590e84614dc2565b8152602061591d818601614b55565b828201526040603f198401121561593357600080fd5b61593b614beb565b925036605f86011261594c57600080fd5b615954614b7e565b80608087013681111561596657600080fd5b604088015b81811015615982578035845292840192840161596b565b50908552604084019490945250509035906001600160401b038211156159a757600080fd5b6159b336838601615786565b60608201526159c460a08501614f12565b60808201529392505050565b600061ffff8083168181036159e7576159e7615346565b6001019392505050565b6000608080830160018060401b038089168552602060018060c01b038916818701526040828916818801526060858189015284895180875260a08a019150848b01965060005b81811015615a735787518051881684528681015162ffffff16878501528581015186850152840151848401529685019691880191600101615a37565b50909d9c50505050505050505050505050565b60006001600160401b038281166002600160401b031981016159e7576159e7615346565b61ffff929092168252602082015260400190565b6001600160601b038181168382160190808211156153be576153be615346565b80820180821115612f9957612f99615346565b6001600160a01b0392831681529116602082015260400190565b8082028115828204841417612f9957612f99615346565b600060408284031215615b3457600080fd5b615b3c614b7e565b8235615b478161541d565b81526020928301359281019290925250919050565b600060208284031215615b6e57600080fd5b8151614ada8161541d565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160a06080840152615bbe60c0840182615239565b608094909401516001600160601b031660a093909301929092525090919050565b6000815180845260005b81811015615c0557602081850181015186830182015201615be9565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000614ada6020830184615bdf565b9182526001600160a01b0316602082015260400190565b60018060401b038516815262ffffff84166020820152826040820152608060608201528151608082015261ffff60208301511660a082015260018060a01b0360408301511660c0820152600060608301516101008060e0850152615cb7610180850183615bdf565b91506080850151615cd2828601826001600160601b03169052565b505060a084015161012084015260c084015161014084015260e08401516101608401528091505095945050505050565b6001600160a01b038c1681526001600160401b038b16602082015262ffffff8a1660408201526060810189905261ffff8816608082015263ffffffff871660a082015260c0810186905260e081018590526101606101008201819052600090615d6d83820187615bdf565b61012084019590955250506001600160601b0391909116610140909101529998505050505050505050565b600060208284031215615daa57600080fd5b5051919050565b65ffffffffffff8181168382160190808211156153be576153be615346565b6001600160601b03929092168252602082015260400190565b815160408201908260005b6002811015614e9d578251825260209283019290910190600101615df4565b634e487b7160e01b600052601260045260246000fd5b600082615e3857615e38615e13565b500490565b6001600160401b0381811683821602808216919082811461575057615750615346565b600082615e6f57615e6f615e13565b500690565b600081518084526020808501945080840160005b838110156150e75781516001600160601b031687529582019590820190600101615e88565b60a081526000615ec060a08301886150b7565b602083820381850152615ed38289615bdf565b915083820360408501528187518084528284019150828160051b850101838a0160005b83811015615f2457601f19878403018552615f12838351615bdf565b94860194925090850190600101615ef6565b50508681036060880152615f38818a615e74565b9450505050508281036080840152611dc681856150b7565b60ff8181168382160190811115612f9957612f99615346565b838152606060208201526000615f8260608301856150b7565b82810360408401526152b48185615bdf565b60006001600160401b03821680615fad57615fad615346565b6000190192915050565b60ff8281168282160390811115612f9957612f9961534656fea164736f6c6343000813000a", -} - -var VRFCoordinatorABI = VRFCoordinatorMetaData.ABI - -var VRFCoordinatorBin = VRFCoordinatorMetaData.Bin - -func DeployVRFCoordinator(auth *bind.TransactOpts, backend bind.ContractBackend, beaconPeriodBlocksArg *big.Int, linkToken common.Address) (common.Address, *types.Transaction, *VRFCoordinator, error) { - parsed, err := VRFCoordinatorMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFCoordinatorBin), backend, beaconPeriodBlocksArg, linkToken) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &VRFCoordinator{VRFCoordinatorCaller: VRFCoordinatorCaller{contract: contract}, VRFCoordinatorTransactor: VRFCoordinatorTransactor{contract: contract}, VRFCoordinatorFilterer: VRFCoordinatorFilterer{contract: contract}}, nil -} - -type VRFCoordinator struct { - address common.Address - abi abi.ABI - VRFCoordinatorCaller - VRFCoordinatorTransactor - VRFCoordinatorFilterer -} - -type VRFCoordinatorCaller struct { - contract *bind.BoundContract -} - -type VRFCoordinatorTransactor struct { - contract *bind.BoundContract -} - -type VRFCoordinatorFilterer struct { - contract *bind.BoundContract -} - -type VRFCoordinatorSession struct { - Contract *VRFCoordinator - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type VRFCoordinatorCallerSession struct { - Contract *VRFCoordinatorCaller - CallOpts bind.CallOpts -} - -type VRFCoordinatorTransactorSession struct { - Contract *VRFCoordinatorTransactor - TransactOpts bind.TransactOpts -} - -type VRFCoordinatorRaw struct { - Contract *VRFCoordinator -} - -type VRFCoordinatorCallerRaw struct { - Contract *VRFCoordinatorCaller -} - -type VRFCoordinatorTransactorRaw struct { - Contract *VRFCoordinatorTransactor -} - -func NewVRFCoordinator(address common.Address, backend bind.ContractBackend) (*VRFCoordinator, error) { - abi, err := abi.JSON(strings.NewReader(VRFCoordinatorABI)) - if err != nil { - return nil, err - } - contract, err := bindVRFCoordinator(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &VRFCoordinator{address: address, abi: abi, VRFCoordinatorCaller: VRFCoordinatorCaller{contract: contract}, VRFCoordinatorTransactor: VRFCoordinatorTransactor{contract: contract}, VRFCoordinatorFilterer: VRFCoordinatorFilterer{contract: contract}}, nil -} - -func NewVRFCoordinatorCaller(address common.Address, caller bind.ContractCaller) (*VRFCoordinatorCaller, error) { - contract, err := bindVRFCoordinator(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &VRFCoordinatorCaller{contract: contract}, nil -} - -func NewVRFCoordinatorTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFCoordinatorTransactor, error) { - contract, err := bindVRFCoordinator(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &VRFCoordinatorTransactor{contract: contract}, nil -} - -func NewVRFCoordinatorFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFCoordinatorFilterer, error) { - contract, err := bindVRFCoordinator(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &VRFCoordinatorFilterer{contract: contract}, nil -} - -func bindVRFCoordinator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := VRFCoordinatorMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_VRFCoordinator *VRFCoordinatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFCoordinator.Contract.VRFCoordinatorCaller.contract.Call(opts, result, method, params...) -} - -func (_VRFCoordinator *VRFCoordinatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFCoordinator.Contract.VRFCoordinatorTransactor.contract.Transfer(opts) -} - -func (_VRFCoordinator *VRFCoordinatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFCoordinator.Contract.VRFCoordinatorTransactor.contract.Transact(opts, method, params...) -} - -func (_VRFCoordinator *VRFCoordinatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFCoordinator.Contract.contract.Call(opts, result, method, params...) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFCoordinator.Contract.contract.Transfer(opts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFCoordinator.Contract.contract.Transact(opts, method, params...) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "MAX_CONSUMERS") - - if err != nil { - return *new(uint16), err - } - - out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) MAXCONSUMERS() (uint16, error) { - return _VRFCoordinator.Contract.MAXCONSUMERS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) MAXCONSUMERS() (uint16, error) { - return _VRFCoordinator.Contract.MAXCONSUMERS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "MAX_NUM_WORDS") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) MAXNUMWORDS() (*big.Int, error) { - return _VRFCoordinator.Contract.MAXNUMWORDS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) MAXNUMWORDS() (*big.Int, error) { - return _VRFCoordinator.Contract.MAXNUMWORDS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "NUM_CONF_DELAYS") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) NUMCONFDELAYS() (uint8, error) { - return _VRFCoordinator.Contract.NUMCONFDELAYS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) NUMCONFDELAYS() (uint8, error) { - return _VRFCoordinator.Contract.NUMCONFDELAYS(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetCallbackMemo(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getCallbackMemo", requestId) - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetCallbackMemo(requestId *big.Int) ([32]byte, error) { - return _VRFCoordinator.Contract.GetCallbackMemo(&_VRFCoordinator.CallOpts, requestId) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetCallbackMemo(requestId *big.Int) ([32]byte, error) { - return _VRFCoordinator.Contract.GetCallbackMemo(&_VRFCoordinator.CallOpts, requestId) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getConfirmationDelays") - - if err != nil { - return *new([8]*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new([8]*big.Int)).(*[8]*big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetConfirmationDelays() ([8]*big.Int, error) { - return _VRFCoordinator.Contract.GetConfirmationDelays(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetConfirmationDelays() ([8]*big.Int, error) { - return _VRFCoordinator.Contract.GetConfirmationDelays(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetFee(opts *bind.CallOpts, arg0 *big.Int, arg1 []byte) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getFee", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetFee(arg0 *big.Int, arg1 []byte) (*big.Int, error) { - return _VRFCoordinator.Contract.GetFee(&_VRFCoordinator.CallOpts, arg0, arg1) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetFee(arg0 *big.Int, arg1 []byte) (*big.Int, error) { - return _VRFCoordinator.Contract.GetFee(&_VRFCoordinator.CallOpts, arg0, arg1) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetFulfillmentFee(opts *bind.CallOpts, arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getFulfillmentFee", arg0, callbackGasLimit, arguments, arg3) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetFulfillmentFee(arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { - return _VRFCoordinator.Contract.GetFulfillmentFee(&_VRFCoordinator.CallOpts, arg0, callbackGasLimit, arguments, arg3) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetFulfillmentFee(arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { - return _VRFCoordinator.Contract.GetFulfillmentFee(&_VRFCoordinator.CallOpts, arg0, callbackGasLimit, arguments, arg3) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetSubscription(opts *bind.CallOpts, subId *big.Int) (GetSubscription, - - error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getSubscription", subId) - - outstruct := new(GetSubscription) - if err != nil { - return *outstruct, err - } - - outstruct.Balance = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.PendingFulfillments = *abi.ConvertType(out[1], new(uint64)).(*uint64) - outstruct.Owner = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) - outstruct.Consumers = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) - - return *outstruct, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetSubscription(subId *big.Int) (GetSubscription, - - error) { - return _VRFCoordinator.Contract.GetSubscription(&_VRFCoordinator.CallOpts, subId) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetSubscription(subId *big.Int) (GetSubscription, - - error) { - return _VRFCoordinator.Contract.GetSubscription(&_VRFCoordinator.CallOpts, subId) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) GetSubscriptionLinkBalance(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "getSubscriptionLinkBalance") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) GetSubscriptionLinkBalance() (*big.Int, error) { - return _VRFCoordinator.Contract.GetSubscriptionLinkBalance(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) GetSubscriptionLinkBalance() (*big.Int, error) { - return _VRFCoordinator.Contract.GetSubscriptionLinkBalance(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "i_beaconPeriodBlocks") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _VRFCoordinator.Contract.IBeaconPeriodBlocks(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) IBeaconPeriodBlocks() (*big.Int, error) { - return _VRFCoordinator.Contract.IBeaconPeriodBlocks(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) ILink(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "i_link") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) ILink() (common.Address, error) { - return _VRFCoordinator.Contract.ILink(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) ILink() (common.Address, error) { - return _VRFCoordinator.Contract.ILink(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) MigrationVersion(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "migrationVersion") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) MigrationVersion() (uint8, error) { - return _VRFCoordinator.Contract.MigrationVersion(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) MigrationVersion() (uint8, error) { - return _VRFCoordinator.Contract.MigrationVersion(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) OnMigration(opts *bind.CallOpts, arg0 []byte) error { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "onMigration", arg0) - - if err != nil { - return err - } - - return err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) OnMigration(arg0 []byte) error { - return _VRFCoordinator.Contract.OnMigration(&_VRFCoordinator.CallOpts, arg0) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) OnMigration(arg0 []byte) error { - return _VRFCoordinator.Contract.OnMigration(&_VRFCoordinator.CallOpts, arg0) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) Owner() (common.Address, error) { - return _VRFCoordinator.Contract.Owner(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) Owner() (common.Address, error) { - return _VRFCoordinator.Contract.Owner(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) SCallbackConfig(opts *bind.CallOpts) (SCallbackConfig, - - error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "s_callbackConfig") - - outstruct := new(SCallbackConfig) - if err != nil { - return *outstruct, err - } - - outstruct.MaxCallbackGasLimit = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.MaxCallbackArgumentsLength = *abi.ConvertType(out[1], new(uint32)).(*uint32) - - return *outstruct, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) SCallbackConfig() (SCallbackConfig, - - error) { - return _VRFCoordinator.Contract.SCallbackConfig(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) SCallbackConfig() (SCallbackConfig, - - error) { - return _VRFCoordinator.Contract.SCallbackConfig(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) SCoordinatorConfig(opts *bind.CallOpts) (SCoordinatorConfig, - - error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "s_coordinatorConfig") - - outstruct := new(SCoordinatorConfig) - if err != nil { - return *outstruct, err - } - - outstruct.UseReasonableGasPrice = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.ReentrancyLock = *abi.ConvertType(out[1], new(bool)).(*bool) - outstruct.Paused = *abi.ConvertType(out[2], new(bool)).(*bool) - outstruct.PremiumPercentage = *abi.ConvertType(out[3], new(uint8)).(*uint8) - outstruct.UnusedGasPenaltyPercent = *abi.ConvertType(out[4], new(uint8)).(*uint8) - outstruct.StalenessSeconds = *abi.ConvertType(out[5], new(uint32)).(*uint32) - outstruct.RedeemableRequestGasOverhead = *abi.ConvertType(out[6], new(uint32)).(*uint32) - outstruct.CallbackRequestGasOverhead = *abi.ConvertType(out[7], new(uint32)).(*uint32) - outstruct.ReasonableGasPriceStalenessBlocks = *abi.ConvertType(out[8], new(uint32)).(*uint32) - outstruct.FallbackWeiPerUnitLink = *abi.ConvertType(out[9], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) SCoordinatorConfig() (SCoordinatorConfig, - - error) { - return _VRFCoordinator.Contract.SCoordinatorConfig(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) SCoordinatorConfig() (SCoordinatorConfig, - - error) { - return _VRFCoordinator.Contract.SCoordinatorConfig(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) SPendingRequests(opts *bind.CallOpts, arg0 *big.Int) (SPendingRequests, - - error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "s_pendingRequests", arg0) - - outstruct := new(SPendingRequests) - if err != nil { - return *outstruct, err - } - - outstruct.SlotNumber = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.ConfirmationDelay = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.NumWords = *abi.ConvertType(out[2], new(uint16)).(*uint16) - outstruct.Requester = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) - - return *outstruct, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) SPendingRequests(arg0 *big.Int) (SPendingRequests, - - error) { - return _VRFCoordinator.Contract.SPendingRequests(&_VRFCoordinator.CallOpts, arg0) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) SPendingRequests(arg0 *big.Int) (SPendingRequests, - - error) { - return _VRFCoordinator.Contract.SPendingRequests(&_VRFCoordinator.CallOpts, arg0) -} - -func (_VRFCoordinator *VRFCoordinatorCaller) SProducer(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFCoordinator.contract.Call(opts, &out, "s_producer") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFCoordinator *VRFCoordinatorSession) SProducer() (common.Address, error) { - return _VRFCoordinator.Contract.SProducer(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorCallerSession) SProducer() (common.Address, error) { - return _VRFCoordinator.Contract.SProducer(&_VRFCoordinator.CallOpts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "acceptOwnership") -} - -func (_VRFCoordinator *VRFCoordinatorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFCoordinator.Contract.AcceptOwnership(&_VRFCoordinator.TransactOpts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFCoordinator.Contract.AcceptOwnership(&_VRFCoordinator.TransactOpts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "acceptSubscriptionOwnerTransfer", subId) -} - -func (_VRFCoordinator *VRFCoordinatorSession) AcceptSubscriptionOwnerTransfer(subId *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinator.TransactOpts, subId) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) AcceptSubscriptionOwnerTransfer(subId *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinator.TransactOpts, subId) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) AddConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "addConsumer", subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorSession) AddConsumer(subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.AddConsumer(&_VRFCoordinator.TransactOpts, subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) AddConsumer(subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.AddConsumer(&_VRFCoordinator.TransactOpts, subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) BatchTransferLink(opts *bind.TransactOpts, recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "batchTransferLink", recipients, paymentsInJuels) -} - -func (_VRFCoordinator *VRFCoordinatorSession) BatchTransferLink(recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.BatchTransferLink(&_VRFCoordinator.TransactOpts, recipients, paymentsInJuels) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) BatchTransferLink(recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.BatchTransferLink(&_VRFCoordinator.TransactOpts, recipients, paymentsInJuels) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) CancelSubscription(opts *bind.TransactOpts, subId *big.Int, to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "cancelSubscription", subId, to) -} - -func (_VRFCoordinator *VRFCoordinatorSession) CancelSubscription(subId *big.Int, to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.CancelSubscription(&_VRFCoordinator.TransactOpts, subId, to) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) CancelSubscription(subId *big.Int, to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.CancelSubscription(&_VRFCoordinator.TransactOpts, subId, to) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "createSubscription") -} - -func (_VRFCoordinator *VRFCoordinatorSession) CreateSubscription() (*types.Transaction, error) { - return _VRFCoordinator.Contract.CreateSubscription(&_VRFCoordinator.TransactOpts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) CreateSubscription() (*types.Transaction, error) { - return _VRFCoordinator.Contract.CreateSubscription(&_VRFCoordinator.TransactOpts) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) DeregisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "deregisterMigratableCoordinator", target) -} - -func (_VRFCoordinator *VRFCoordinatorSession) DeregisterMigratableCoordinator(target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.DeregisterMigratableCoordinator(&_VRFCoordinator.TransactOpts, target) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) DeregisterMigratableCoordinator(target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.DeregisterMigratableCoordinator(&_VRFCoordinator.TransactOpts, target) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) Migrate(opts *bind.TransactOpts, newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "migrate", newCoordinator, encodedRequest) -} - -func (_VRFCoordinator *VRFCoordinatorSession) Migrate(newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.Migrate(&_VRFCoordinator.TransactOpts, newCoordinator, encodedRequest) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) Migrate(newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.Migrate(&_VRFCoordinator.TransactOpts, newCoordinator, encodedRequest) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "onTokenTransfer", arg0, amount, data) -} - -func (_VRFCoordinator *VRFCoordinatorSession) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.OnTokenTransfer(&_VRFCoordinator.TransactOpts, arg0, amount, data) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.OnTokenTransfer(&_VRFCoordinator.TransactOpts, arg0, amount, data) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) ProcessVRFOutputs(opts *bind.TransactOpts, vrfOutputs []VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "processVRFOutputs", vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) -} - -func (_VRFCoordinator *VRFCoordinatorSession) ProcessVRFOutputs(vrfOutputs []VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { - return _VRFCoordinator.Contract.ProcessVRFOutputs(&_VRFCoordinator.TransactOpts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) ProcessVRFOutputs(vrfOutputs []VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { - return _VRFCoordinator.Contract.ProcessVRFOutputs(&_VRFCoordinator.TransactOpts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "redeemRandomness", subID, requestID, arg2) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RedeemRandomness(subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RedeemRandomness(&_VRFCoordinator.TransactOpts, subID, requestID, arg2) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RedeemRandomness(subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RedeemRandomness(&_VRFCoordinator.TransactOpts, subID, requestID, arg2) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "registerMigratableCoordinator", target) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RegisterMigratableCoordinator(target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RegisterMigratableCoordinator(&_VRFCoordinator.TransactOpts, target) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RegisterMigratableCoordinator(target common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RegisterMigratableCoordinator(&_VRFCoordinator.TransactOpts, target) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "removeConsumer", subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RemoveConsumer(subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RemoveConsumer(&_VRFCoordinator.TransactOpts, subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RemoveConsumer(subId *big.Int, consumer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RemoveConsumer(&_VRFCoordinator.TransactOpts, subId, consumer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RequestRandomness(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "requestRandomness", subID, numWords, confDelay, arg3) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RequestRandomness(subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestRandomness(&_VRFCoordinator.TransactOpts, subID, numWords, confDelay, arg3) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RequestRandomness(subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestRandomness(&_VRFCoordinator.TransactOpts, subID, numWords, confDelay, arg3) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "requestRandomnessFulfillment", subID, numWords, confDelay, callbackGasLimit, arguments, arg5) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestRandomnessFulfillment(&_VRFCoordinator.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RequestRandomnessFulfillment(subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestRandomnessFulfillment(&_VRFCoordinator.TransactOpts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "requestSubscriptionOwnerTransfer", subId, newOwner) -} - -func (_VRFCoordinator *VRFCoordinatorSession) RequestSubscriptionOwnerTransfer(subId *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinator.TransactOpts, subId, newOwner) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) RequestSubscriptionOwnerTransfer(subId *big.Int, newOwner common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinator.TransactOpts, subId, newOwner) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) SetCallbackConfig(opts *bind.TransactOpts, config VRFCoordinatorCallbackConfig) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "setCallbackConfig", config) -} - -func (_VRFCoordinator *VRFCoordinatorSession) SetCallbackConfig(config VRFCoordinatorCallbackConfig) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetCallbackConfig(&_VRFCoordinator.TransactOpts, config) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) SetCallbackConfig(config VRFCoordinatorCallbackConfig) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetCallbackConfig(&_VRFCoordinator.TransactOpts, config) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) SetConfirmationDelays(opts *bind.TransactOpts, confDelays [8]*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "setConfirmationDelays", confDelays) -} - -func (_VRFCoordinator *VRFCoordinatorSession) SetConfirmationDelays(confDelays [8]*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetConfirmationDelays(&_VRFCoordinator.TransactOpts, confDelays) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) SetConfirmationDelays(confDelays [8]*big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetConfirmationDelays(&_VRFCoordinator.TransactOpts, confDelays) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) SetCoordinatorConfig(opts *bind.TransactOpts, coordinatorConfig VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "setCoordinatorConfig", coordinatorConfig) -} - -func (_VRFCoordinator *VRFCoordinatorSession) SetCoordinatorConfig(coordinatorConfig VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetCoordinatorConfig(&_VRFCoordinator.TransactOpts, coordinatorConfig) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) SetCoordinatorConfig(coordinatorConfig VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetCoordinatorConfig(&_VRFCoordinator.TransactOpts, coordinatorConfig) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) SetPauseFlag(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "setPauseFlag", pause) -} - -func (_VRFCoordinator *VRFCoordinatorSession) SetPauseFlag(pause bool) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetPauseFlag(&_VRFCoordinator.TransactOpts, pause) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) SetPauseFlag(pause bool) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetPauseFlag(&_VRFCoordinator.TransactOpts, pause) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) SetProducer(opts *bind.TransactOpts, producer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "setProducer", producer) -} - -func (_VRFCoordinator *VRFCoordinatorSession) SetProducer(producer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetProducer(&_VRFCoordinator.TransactOpts, producer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) SetProducer(producer common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.SetProducer(&_VRFCoordinator.TransactOpts, producer) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) TransferLink(opts *bind.TransactOpts, recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "transferLink", recipient, juelsAmount) -} - -func (_VRFCoordinator *VRFCoordinatorSession) TransferLink(recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.TransferLink(&_VRFCoordinator.TransactOpts, recipient, juelsAmount) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) TransferLink(recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { - return _VRFCoordinator.Contract.TransferLink(&_VRFCoordinator.TransactOpts, recipient, juelsAmount) -} - -func (_VRFCoordinator *VRFCoordinatorTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.contract.Transact(opts, "transferOwnership", to) -} - -func (_VRFCoordinator *VRFCoordinatorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.TransferOwnership(&_VRFCoordinator.TransactOpts, to) -} - -func (_VRFCoordinator *VRFCoordinatorTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFCoordinator.Contract.TransferOwnership(&_VRFCoordinator.TransactOpts, to) -} - -type VRFCoordinatorCallbackConfigSetIterator struct { - Event *VRFCoordinatorCallbackConfigSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorCallbackConfigSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorCallbackConfigSet) - 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(VRFCoordinatorCallbackConfigSet) - 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 *VRFCoordinatorCallbackConfigSetIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorCallbackConfigSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorCallbackConfigSet struct { - NewConfig VRFCoordinatorCallbackConfig - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterCallbackConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorCallbackConfigSetIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "CallbackConfigSet") - if err != nil { - return nil, err - } - return &VRFCoordinatorCallbackConfigSetIterator{contract: _VRFCoordinator.contract, event: "CallbackConfigSet", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchCallbackConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCallbackConfigSet) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "CallbackConfigSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorCallbackConfigSet) - if err := _VRFCoordinator.contract.UnpackLog(event, "CallbackConfigSet", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseCallbackConfigSet(log types.Log) (*VRFCoordinatorCallbackConfigSet, error) { - event := new(VRFCoordinatorCallbackConfigSet) - if err := _VRFCoordinator.contract.UnpackLog(event, "CallbackConfigSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorCoordinatorConfigSetIterator struct { - Event *VRFCoordinatorCoordinatorConfigSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorCoordinatorConfigSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorCoordinatorConfigSet) - 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(VRFCoordinatorCoordinatorConfigSet) - 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 *VRFCoordinatorCoordinatorConfigSetIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorCoordinatorConfigSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorCoordinatorConfigSet struct { - CoordinatorConfig VRFBeaconTypesCoordinatorConfig - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterCoordinatorConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorConfigSetIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "CoordinatorConfigSet") - if err != nil { - return nil, err - } - return &VRFCoordinatorCoordinatorConfigSetIterator{contract: _VRFCoordinator.contract, event: "CoordinatorConfigSet", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchCoordinatorConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "CoordinatorConfigSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorCoordinatorConfigSet) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorConfigSet", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseCoordinatorConfigSet(log types.Log) (*VRFCoordinatorCoordinatorConfigSet, error) { - event := new(VRFCoordinatorCoordinatorConfigSet) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorConfigSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorCoordinatorDeregisteredIterator struct { - Event *VRFCoordinatorCoordinatorDeregistered - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorCoordinatorDeregisteredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorCoordinatorDeregistered) - 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(VRFCoordinatorCoordinatorDeregistered) - 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 *VRFCoordinatorCoordinatorDeregisteredIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorCoordinatorDeregisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorCoordinatorDeregistered struct { - CoordinatorAddress common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterCoordinatorDeregistered(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorDeregisteredIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "CoordinatorDeregistered") - if err != nil { - return nil, err - } - return &VRFCoordinatorCoordinatorDeregisteredIterator{contract: _VRFCoordinator.contract, event: "CoordinatorDeregistered", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchCoordinatorDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "CoordinatorDeregistered") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorCoordinatorDeregistered) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorDeregistered", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseCoordinatorDeregistered(log types.Log) (*VRFCoordinatorCoordinatorDeregistered, error) { - event := new(VRFCoordinatorCoordinatorDeregistered) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorDeregistered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorCoordinatorRegisteredIterator struct { - Event *VRFCoordinatorCoordinatorRegistered - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorCoordinatorRegisteredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorCoordinatorRegistered) - 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(VRFCoordinatorCoordinatorRegistered) - 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 *VRFCoordinatorCoordinatorRegisteredIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorCoordinatorRegisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorCoordinatorRegistered struct { - CoordinatorAddress common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterCoordinatorRegistered(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorRegisteredIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "CoordinatorRegistered") - if err != nil { - return nil, err - } - return &VRFCoordinatorCoordinatorRegisteredIterator{contract: _VRFCoordinator.contract, event: "CoordinatorRegistered", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchCoordinatorRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorRegistered) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "CoordinatorRegistered") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorCoordinatorRegistered) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorRegistered", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseCoordinatorRegistered(log types.Log) (*VRFCoordinatorCoordinatorRegistered, error) { - event := new(VRFCoordinatorCoordinatorRegistered) - if err := _VRFCoordinator.contract.UnpackLog(event, "CoordinatorRegistered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorMigrationCompletedIterator struct { - Event *VRFCoordinatorMigrationCompleted - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorMigrationCompletedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorMigrationCompleted) - 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(VRFCoordinatorMigrationCompleted) - 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 *VRFCoordinatorMigrationCompletedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorMigrationCompletedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorMigrationCompleted struct { - NewVersion uint8 - NewCoordinator common.Address - SubID *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterMigrationCompleted(opts *bind.FilterOpts, newVersion []uint8, subID []*big.Int) (*VRFCoordinatorMigrationCompletedIterator, error) { - - var newVersionRule []interface{} - for _, newVersionItem := range newVersion { - newVersionRule = append(newVersionRule, newVersionItem) - } - - var subIDRule []interface{} - for _, subIDItem := range subID { - subIDRule = append(subIDRule, subIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "MigrationCompleted", newVersionRule, subIDRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorMigrationCompletedIterator{contract: _VRFCoordinator.contract, event: "MigrationCompleted", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchMigrationCompleted(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorMigrationCompleted, newVersion []uint8, subID []*big.Int) (event.Subscription, error) { - - var newVersionRule []interface{} - for _, newVersionItem := range newVersion { - newVersionRule = append(newVersionRule, newVersionItem) - } - - var subIDRule []interface{} - for _, subIDItem := range subID { - subIDRule = append(subIDRule, subIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "MigrationCompleted", newVersionRule, subIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorMigrationCompleted) - if err := _VRFCoordinator.contract.UnpackLog(event, "MigrationCompleted", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseMigrationCompleted(log types.Log) (*VRFCoordinatorMigrationCompleted, error) { - event := new(VRFCoordinatorMigrationCompleted) - if err := _VRFCoordinator.contract.UnpackLog(event, "MigrationCompleted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorOutputsServedIterator struct { - Event *VRFCoordinatorOutputsServed - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorOutputsServedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorOutputsServed) - 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(VRFCoordinatorOutputsServed) - 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 *VRFCoordinatorOutputsServedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorOutputsServedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorOutputsServed struct { - RecentBlockHeight uint64 - JuelsPerFeeCoin *big.Int - ReasonableGasPrice uint64 - OutputsServed []VRFBeaconTypesOutputServed - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterOutputsServed(opts *bind.FilterOpts) (*VRFCoordinatorOutputsServedIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "OutputsServed") - if err != nil { - return nil, err - } - return &VRFCoordinatorOutputsServedIterator{contract: _VRFCoordinator.contract, event: "OutputsServed", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOutputsServed) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "OutputsServed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorOutputsServed) - if err := _VRFCoordinator.contract.UnpackLog(event, "OutputsServed", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseOutputsServed(log types.Log) (*VRFCoordinatorOutputsServed, error) { - event := new(VRFCoordinatorOutputsServed) - if err := _VRFCoordinator.contract.UnpackLog(event, "OutputsServed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorOwnershipTransferRequestedIterator struct { - Event *VRFCoordinatorOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorOwnershipTransferRequested) - 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(VRFCoordinatorOwnershipTransferRequested) - 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 *VRFCoordinatorOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorOwnershipTransferRequestedIterator{contract: _VRFCoordinator.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorOwnershipTransferRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorOwnershipTransferRequested, error) { - event := new(VRFCoordinatorOwnershipTransferRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorOwnershipTransferredIterator struct { - Event *VRFCoordinatorOwnershipTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorOwnershipTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorOwnershipTransferred) - 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(VRFCoordinatorOwnershipTransferred) - 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 *VRFCoordinatorOwnershipTransferredIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorOwnershipTransferredIterator{contract: _VRFCoordinator.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorOwnershipTransferred) - if err := _VRFCoordinator.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorOwnershipTransferred, error) { - event := new(VRFCoordinatorOwnershipTransferred) - if err := _VRFCoordinator.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorPauseFlagChangedIterator struct { - Event *VRFCoordinatorPauseFlagChanged - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorPauseFlagChangedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorPauseFlagChanged) - 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(VRFCoordinatorPauseFlagChanged) - 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 *VRFCoordinatorPauseFlagChangedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorPauseFlagChangedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorPauseFlagChanged struct { - Paused bool - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterPauseFlagChanged(opts *bind.FilterOpts) (*VRFCoordinatorPauseFlagChangedIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "PauseFlagChanged") - if err != nil { - return nil, err - } - return &VRFCoordinatorPauseFlagChangedIterator{contract: _VRFCoordinator.contract, event: "PauseFlagChanged", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchPauseFlagChanged(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorPauseFlagChanged) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "PauseFlagChanged") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorPauseFlagChanged) - if err := _VRFCoordinator.contract.UnpackLog(event, "PauseFlagChanged", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParsePauseFlagChanged(log types.Log) (*VRFCoordinatorPauseFlagChanged, error) { - event := new(VRFCoordinatorPauseFlagChanged) - if err := _VRFCoordinator.contract.UnpackLog(event, "PauseFlagChanged", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorRandomWordsFulfilledIterator struct { - Event *VRFCoordinatorRandomWordsFulfilled - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorRandomWordsFulfilledIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorRandomWordsFulfilled) - 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(VRFCoordinatorRandomWordsFulfilled) - 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 *VRFCoordinatorRandomWordsFulfilledIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorRandomWordsFulfilledIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorRandomWordsFulfilled struct { - RequestIDs []*big.Int - SuccessfulFulfillment []byte - TruncatedErrorData [][]byte - SubBalances []*big.Int - SubIDs []*big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*VRFCoordinatorRandomWordsFulfilledIterator, error) { - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "RandomWordsFulfilled") - if err != nil { - return nil, err - } - return &VRFCoordinatorRandomWordsFulfilledIterator{contract: _VRFCoordinator.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error) { - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "RandomWordsFulfilled") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorRandomWordsFulfilled) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorRandomWordsFulfilled, error) { - event := new(VRFCoordinatorRandomWordsFulfilled) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorRandomnessFulfillmentRequestedIterator struct { - Event *VRFCoordinatorRandomnessFulfillmentRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorRandomnessFulfillmentRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorRandomnessFulfillmentRequested) - 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(VRFCoordinatorRandomnessFulfillmentRequested) - 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 *VRFCoordinatorRandomnessFulfillmentRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorRandomnessFulfillmentRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorRandomnessFulfillmentRequested struct { - RequestID *big.Int - Requester common.Address - NextBeaconOutputHeight uint64 - ConfDelay *big.Int - SubID *big.Int - NumWords uint16 - GasAllowance uint32 - GasPrice *big.Int - WeiPerUnitLink *big.Int - Arguments []byte - CostJuels *big.Int - NewSubBalance *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFCoordinatorRandomnessFulfillmentRequestedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "RandomnessFulfillmentRequested", requestIDRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorRandomnessFulfillmentRequestedIterator{contract: _VRFCoordinator.contract, event: "RandomnessFulfillmentRequested", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "RandomnessFulfillmentRequested", requestIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorRandomnessFulfillmentRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessFulfillmentRequested", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseRandomnessFulfillmentRequested(log types.Log) (*VRFCoordinatorRandomnessFulfillmentRequested, error) { - event := new(VRFCoordinatorRandomnessFulfillmentRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessFulfillmentRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorRandomnessRedeemedIterator struct { - Event *VRFCoordinatorRandomnessRedeemed - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorRandomnessRedeemedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorRandomnessRedeemed) - 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(VRFCoordinatorRandomnessRedeemed) - 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 *VRFCoordinatorRandomnessRedeemedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorRandomnessRedeemedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorRandomnessRedeemed struct { - RequestID *big.Int - Requester common.Address - SubID *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*VRFCoordinatorRandomnessRedeemedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - var requesterRule []interface{} - for _, requesterItem := range requester { - requesterRule = append(requesterRule, requesterItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "RandomnessRedeemed", requestIDRule, requesterRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorRandomnessRedeemedIterator{contract: _VRFCoordinator.contract, event: "RandomnessRedeemed", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - var requesterRule []interface{} - for _, requesterItem := range requester { - requesterRule = append(requesterRule, requesterItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "RandomnessRedeemed", requestIDRule, requesterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorRandomnessRedeemed) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessRedeemed", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseRandomnessRedeemed(log types.Log) (*VRFCoordinatorRandomnessRedeemed, error) { - event := new(VRFCoordinatorRandomnessRedeemed) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessRedeemed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorRandomnessRequestedIterator struct { - Event *VRFCoordinatorRandomnessRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorRandomnessRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorRandomnessRequested) - 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(VRFCoordinatorRandomnessRequested) - 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 *VRFCoordinatorRandomnessRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorRandomnessRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorRandomnessRequested struct { - RequestID *big.Int - Requester common.Address - NextBeaconOutputHeight uint64 - ConfDelay *big.Int - SubID *big.Int - NumWords uint16 - CostJuels *big.Int - NewSubBalance *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFCoordinatorRandomnessRequestedIterator, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "RandomnessRequested", requestIDRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorRandomnessRequestedIterator{contract: _VRFCoordinator.contract, event: "RandomnessRequested", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { - - var requestIDRule []interface{} - for _, requestIDItem := range requestID { - requestIDRule = append(requestIDRule, requestIDItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "RandomnessRequested", requestIDRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorRandomnessRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessRequested", 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 (_VRFCoordinator *VRFCoordinatorFilterer) ParseRandomnessRequested(log types.Log) (*VRFCoordinatorRandomnessRequested, error) { - event := new(VRFCoordinatorRandomnessRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "RandomnessRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionCanceledIterator struct { - Event *VRFCoordinatorSubscriptionCanceled - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionCanceledIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionCanceled) - 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(VRFCoordinatorSubscriptionCanceled) - 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 *VRFCoordinatorSubscriptionCanceledIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionCanceledIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionCanceled struct { - SubId *big.Int - To common.Address - Amount *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionCanceledIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionCanceled", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionCanceledIterator{contract: _VRFCoordinator.contract, event: "SubscriptionCanceled", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionCanceled, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionCanceled", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionCanceled) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionCanceled", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorSubscriptionCanceled, error) { - event := new(VRFCoordinatorSubscriptionCanceled) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionCanceled", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionConsumerAddedIterator struct { - Event *VRFCoordinatorSubscriptionConsumerAdded - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionConsumerAddedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionConsumerAdded) - 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(VRFCoordinatorSubscriptionConsumerAdded) - 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 *VRFCoordinatorSubscriptionConsumerAddedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionConsumerAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionConsumerAdded struct { - SubId *big.Int - Consumer common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionConsumerAddedIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionConsumerAdded", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionConsumerAddedIterator{contract: _VRFCoordinator.contract, event: "SubscriptionConsumerAdded", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionConsumerAdded, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionConsumerAdded", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionConsumerAdded) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionConsumerAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorSubscriptionConsumerAdded, error) { - event := new(VRFCoordinatorSubscriptionConsumerAdded) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionConsumerAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionConsumerRemovedIterator struct { - Event *VRFCoordinatorSubscriptionConsumerRemoved - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionConsumerRemovedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionConsumerRemoved) - 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(VRFCoordinatorSubscriptionConsumerRemoved) - 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 *VRFCoordinatorSubscriptionConsumerRemovedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionConsumerRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionConsumerRemoved struct { - SubId *big.Int - Consumer common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionConsumerRemovedIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionConsumerRemoved", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionConsumerRemovedIterator{contract: _VRFCoordinator.contract, event: "SubscriptionConsumerRemoved", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionConsumerRemoved, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionConsumerRemoved", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionConsumerRemoved) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionConsumerRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorSubscriptionConsumerRemoved, error) { - event := new(VRFCoordinatorSubscriptionConsumerRemoved) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionConsumerRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionCreatedIterator struct { - Event *VRFCoordinatorSubscriptionCreated - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionCreatedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionCreated) - 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(VRFCoordinatorSubscriptionCreated) - 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 *VRFCoordinatorSubscriptionCreatedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionCreatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionCreated struct { - SubId *big.Int - Owner common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []*big.Int, owner []common.Address) (*VRFCoordinatorSubscriptionCreatedIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionCreated", subIdRule, ownerRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionCreatedIterator{contract: _VRFCoordinator.contract, event: "SubscriptionCreated", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionCreated, subId []*big.Int, owner []common.Address) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionCreated", subIdRule, ownerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionCreated) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionCreated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorSubscriptionCreated, error) { - event := new(VRFCoordinatorSubscriptionCreated) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionCreated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionFundedIterator struct { - Event *VRFCoordinatorSubscriptionFunded - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionFundedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionFunded) - 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(VRFCoordinatorSubscriptionFunded) - 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 *VRFCoordinatorSubscriptionFundedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionFundedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionFunded struct { - SubId *big.Int - OldBalance *big.Int - NewBalance *big.Int - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionFundedIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionFunded", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionFundedIterator{contract: _VRFCoordinator.contract, event: "SubscriptionFunded", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionFunded, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionFunded", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionFunded) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionFunded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorSubscriptionFunded, error) { - event := new(VRFCoordinatorSubscriptionFunded) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionFunded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionOwnerTransferRequestedIterator struct { - Event *VRFCoordinatorSubscriptionOwnerTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionOwnerTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionOwnerTransferRequested) - 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(VRFCoordinatorSubscriptionOwnerTransferRequested) - 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 *VRFCoordinatorSubscriptionOwnerTransferRequestedIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionOwnerTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionOwnerTransferRequested struct { - SubId *big.Int - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionOwnerTransferRequestedIterator{contract: _VRFCoordinator.contract, event: "SubscriptionOwnerTransferRequested", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionOwnerTransferRequested, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionOwnerTransferRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorSubscriptionOwnerTransferRequested, error) { - event := new(VRFCoordinatorSubscriptionOwnerTransferRequested) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type VRFCoordinatorSubscriptionOwnerTransferredIterator struct { - Event *VRFCoordinatorSubscriptionOwnerTransferred - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFCoordinatorSubscriptionOwnerTransferredIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFCoordinatorSubscriptionOwnerTransferred) - 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(VRFCoordinatorSubscriptionOwnerTransferred) - 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 *VRFCoordinatorSubscriptionOwnerTransferredIterator) Error() error { - return it.fail -} - -func (it *VRFCoordinatorSubscriptionOwnerTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFCoordinatorSubscriptionOwnerTransferred struct { - SubId *big.Int - From common.Address - To common.Address - Raw types.Log -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionOwnerTransferredIterator, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.FilterLogs(opts, "SubscriptionOwnerTransferred", subIdRule) - if err != nil { - return nil, err - } - return &VRFCoordinatorSubscriptionOwnerTransferredIterator{contract: _VRFCoordinator.contract, event: "SubscriptionOwnerTransferred", logs: logs, sub: sub}, nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionOwnerTransferred, subId []*big.Int) (event.Subscription, error) { - - var subIdRule []interface{} - for _, subIdItem := range subId { - subIdRule = append(subIdRule, subIdItem) - } - - logs, sub, err := _VRFCoordinator.contract.WatchLogs(opts, "SubscriptionOwnerTransferred", subIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFCoordinatorSubscriptionOwnerTransferred) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionOwnerTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFCoordinator *VRFCoordinatorFilterer) ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorSubscriptionOwnerTransferred, error) { - event := new(VRFCoordinatorSubscriptionOwnerTransferred) - if err := _VRFCoordinator.contract.UnpackLog(event, "SubscriptionOwnerTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type GetSubscription struct { - Balance *big.Int - PendingFulfillments uint64 - Owner common.Address - Consumers []common.Address -} -type SCallbackConfig struct { - MaxCallbackGasLimit uint32 - MaxCallbackArgumentsLength uint32 -} -type SCoordinatorConfig struct { - UseReasonableGasPrice bool - ReentrancyLock bool - Paused bool - PremiumPercentage uint8 - UnusedGasPenaltyPercent uint8 - StalenessSeconds uint32 - RedeemableRequestGasOverhead uint32 - CallbackRequestGasOverhead uint32 - ReasonableGasPriceStalenessBlocks uint32 - FallbackWeiPerUnitLink *big.Int -} -type SPendingRequests struct { - SlotNumber uint32 - ConfirmationDelay *big.Int - NumWords uint16 - Requester common.Address -} - -func (_VRFCoordinator *VRFCoordinator) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _VRFCoordinator.abi.Events["CallbackConfigSet"].ID: - return _VRFCoordinator.ParseCallbackConfigSet(log) - case _VRFCoordinator.abi.Events["CoordinatorConfigSet"].ID: - return _VRFCoordinator.ParseCoordinatorConfigSet(log) - case _VRFCoordinator.abi.Events["CoordinatorDeregistered"].ID: - return _VRFCoordinator.ParseCoordinatorDeregistered(log) - case _VRFCoordinator.abi.Events["CoordinatorRegistered"].ID: - return _VRFCoordinator.ParseCoordinatorRegistered(log) - case _VRFCoordinator.abi.Events["MigrationCompleted"].ID: - return _VRFCoordinator.ParseMigrationCompleted(log) - case _VRFCoordinator.abi.Events["OutputsServed"].ID: - return _VRFCoordinator.ParseOutputsServed(log) - case _VRFCoordinator.abi.Events["OwnershipTransferRequested"].ID: - return _VRFCoordinator.ParseOwnershipTransferRequested(log) - case _VRFCoordinator.abi.Events["OwnershipTransferred"].ID: - return _VRFCoordinator.ParseOwnershipTransferred(log) - case _VRFCoordinator.abi.Events["PauseFlagChanged"].ID: - return _VRFCoordinator.ParsePauseFlagChanged(log) - case _VRFCoordinator.abi.Events["RandomWordsFulfilled"].ID: - return _VRFCoordinator.ParseRandomWordsFulfilled(log) - case _VRFCoordinator.abi.Events["RandomnessFulfillmentRequested"].ID: - return _VRFCoordinator.ParseRandomnessFulfillmentRequested(log) - case _VRFCoordinator.abi.Events["RandomnessRedeemed"].ID: - return _VRFCoordinator.ParseRandomnessRedeemed(log) - case _VRFCoordinator.abi.Events["RandomnessRequested"].ID: - return _VRFCoordinator.ParseRandomnessRequested(log) - case _VRFCoordinator.abi.Events["SubscriptionCanceled"].ID: - return _VRFCoordinator.ParseSubscriptionCanceled(log) - case _VRFCoordinator.abi.Events["SubscriptionConsumerAdded"].ID: - return _VRFCoordinator.ParseSubscriptionConsumerAdded(log) - case _VRFCoordinator.abi.Events["SubscriptionConsumerRemoved"].ID: - return _VRFCoordinator.ParseSubscriptionConsumerRemoved(log) - case _VRFCoordinator.abi.Events["SubscriptionCreated"].ID: - return _VRFCoordinator.ParseSubscriptionCreated(log) - case _VRFCoordinator.abi.Events["SubscriptionFunded"].ID: - return _VRFCoordinator.ParseSubscriptionFunded(log) - case _VRFCoordinator.abi.Events["SubscriptionOwnerTransferRequested"].ID: - return _VRFCoordinator.ParseSubscriptionOwnerTransferRequested(log) - case _VRFCoordinator.abi.Events["SubscriptionOwnerTransferred"].ID: - return _VRFCoordinator.ParseSubscriptionOwnerTransferred(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (VRFCoordinatorCallbackConfigSet) Topic() common.Hash { - return common.HexToHash("0x0cc54509a45ab33cd67614d4a2892c083ecf8fb43b9d29f6ea8130b9023e51df") -} - -func (VRFCoordinatorCoordinatorConfigSet) Topic() common.Hash { - return common.HexToHash("0x0028d3a46e95e67def989d41c66eb331add9809460b95b5fb4eb006157728fc5") -} - -func (VRFCoordinatorCoordinatorDeregistered) Topic() common.Hash { - return common.HexToHash("0xf80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37") -} - -func (VRFCoordinatorCoordinatorRegistered) Topic() common.Hash { - return common.HexToHash("0xb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af01625") -} - -func (VRFCoordinatorMigrationCompleted) Topic() common.Hash { - return common.HexToHash("0xbd89b747474d3fc04664dfbd1d56ae7ffbe46ee097cdb9979c13916bb76269ce") -} - -func (VRFCoordinatorOutputsServed) Topic() common.Hash { - return common.HexToHash("0xf10ea936d00579b4c52035ee33bf46929646b3aa87554c565d8fb2c7aa549c44") -} - -func (VRFCoordinatorOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (VRFCoordinatorOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") -} - -func (VRFCoordinatorPauseFlagChanged) Topic() common.Hash { - return common.HexToHash("0x49ba7c1de2d8853088b6270e43df2118516b217f38b917dd2b80dea360860fbe") -} - -func (VRFCoordinatorRandomWordsFulfilled) Topic() common.Hash { - return common.HexToHash("0x8f79f730779e875ce76c428039cc2052b5b5918c2a55c598fab251c1198aec54") -} - -func (VRFCoordinatorRandomnessFulfillmentRequested) Topic() common.Hash { - return common.HexToHash("0x01872fb9c7d6d68af06a17347935e04412da302a377224c205e672c26e18c37f") -} - -func (VRFCoordinatorRandomnessRedeemed) Topic() common.Hash { - return common.HexToHash("0x16f3f633197fafab10a5df69e6f3f2f7f20092f08d8d47de0a91c0f4b96a1a25") -} - -func (VRFCoordinatorRandomnessRequested) Topic() common.Hash { - return common.HexToHash("0xb7933fba96b6b452eb44f99fdc08052a45dff82363d59abaff0456931c3d2459") -} - -func (VRFCoordinatorSubscriptionCanceled) Topic() common.Hash { - return common.HexToHash("0x3784f77e8e883de95b5d47cd713ced01229fa74d118c0a462224bcb0516d43f1") -} - -func (VRFCoordinatorSubscriptionConsumerAdded) Topic() common.Hash { - return common.HexToHash("0x1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1") -} - -func (VRFCoordinatorSubscriptionConsumerRemoved) Topic() common.Hash { - return common.HexToHash("0x32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7") -} - -func (VRFCoordinatorSubscriptionCreated) Topic() common.Hash { - return common.HexToHash("0x1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d") -} - -func (VRFCoordinatorSubscriptionFunded) Topic() common.Hash { - return common.HexToHash("0x1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a") -} - -func (VRFCoordinatorSubscriptionOwnerTransferRequested) Topic() common.Hash { - return common.HexToHash("0x21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a1") -} - -func (VRFCoordinatorSubscriptionOwnerTransferred) Topic() common.Hash { - return common.HexToHash("0xd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c9386") -} - -func (_VRFCoordinator *VRFCoordinator) Address() common.Address { - return _VRFCoordinator.address -} - -type VRFCoordinatorInterface interface { - MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) - - MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, error) - - NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) - - GetCallbackMemo(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) - - GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) - - GetFee(opts *bind.CallOpts, arg0 *big.Int, arg1 []byte) (*big.Int, error) - - GetFulfillmentFee(opts *bind.CallOpts, arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) - - GetSubscription(opts *bind.CallOpts, subId *big.Int) (GetSubscription, - - error) - - GetSubscriptionLinkBalance(opts *bind.CallOpts) (*big.Int, error) - - IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) - - ILink(opts *bind.CallOpts) (common.Address, error) - - MigrationVersion(opts *bind.CallOpts) (uint8, error) - - OnMigration(opts *bind.CallOpts, arg0 []byte) error - - Owner(opts *bind.CallOpts) (common.Address, error) - - SCallbackConfig(opts *bind.CallOpts) (SCallbackConfig, - - error) - - SCoordinatorConfig(opts *bind.CallOpts) (SCoordinatorConfig, - - error) - - SPendingRequests(opts *bind.CallOpts, arg0 *big.Int) (SPendingRequests, - - error) - - SProducer(opts *bind.CallOpts) (common.Address, error) - - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - - AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) - - AddConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) - - BatchTransferLink(opts *bind.TransactOpts, recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) - - CancelSubscription(opts *bind.TransactOpts, subId *big.Int, to common.Address) (*types.Transaction, error) - - CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) - - DeregisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) - - Migrate(opts *bind.TransactOpts, newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) - - OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) - - ProcessVRFOutputs(opts *bind.TransactOpts, vrfOutputs []VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) - - RedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) - - RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) - - RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) - - RequestRandomness(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) - - RequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) - - RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int, newOwner common.Address) (*types.Transaction, error) - - SetCallbackConfig(opts *bind.TransactOpts, config VRFCoordinatorCallbackConfig) (*types.Transaction, error) - - SetConfirmationDelays(opts *bind.TransactOpts, confDelays [8]*big.Int) (*types.Transaction, error) - - SetCoordinatorConfig(opts *bind.TransactOpts, coordinatorConfig VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) - - SetPauseFlag(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) - - SetProducer(opts *bind.TransactOpts, producer common.Address) (*types.Transaction, error) - - TransferLink(opts *bind.TransactOpts, recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - - FilterCallbackConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorCallbackConfigSetIterator, error) - - WatchCallbackConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCallbackConfigSet) (event.Subscription, error) - - ParseCallbackConfigSet(log types.Log) (*VRFCoordinatorCallbackConfigSet, error) - - FilterCoordinatorConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorConfigSetIterator, error) - - WatchCoordinatorConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error) - - ParseCoordinatorConfigSet(log types.Log) (*VRFCoordinatorCoordinatorConfigSet, error) - - FilterCoordinatorDeregistered(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorDeregisteredIterator, error) - - WatchCoordinatorDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error) - - ParseCoordinatorDeregistered(log types.Log) (*VRFCoordinatorCoordinatorDeregistered, error) - - FilterCoordinatorRegistered(opts *bind.FilterOpts) (*VRFCoordinatorCoordinatorRegisteredIterator, error) - - WatchCoordinatorRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorCoordinatorRegistered) (event.Subscription, error) - - ParseCoordinatorRegistered(log types.Log) (*VRFCoordinatorCoordinatorRegistered, error) - - FilterMigrationCompleted(opts *bind.FilterOpts, newVersion []uint8, subID []*big.Int) (*VRFCoordinatorMigrationCompletedIterator, error) - - WatchMigrationCompleted(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorMigrationCompleted, newVersion []uint8, subID []*big.Int) (event.Subscription, error) - - ParseMigrationCompleted(log types.Log) (*VRFCoordinatorMigrationCompleted, error) - - FilterOutputsServed(opts *bind.FilterOpts) (*VRFCoordinatorOutputsServedIterator, error) - - WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOutputsServed) (event.Subscription, error) - - ParseOutputsServed(log types.Log) (*VRFCoordinatorOutputsServed, error) - - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorOwnershipTransferRequested, error) - - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorOwnershipTransferredIterator, error) - - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) - - ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorOwnershipTransferred, error) - - FilterPauseFlagChanged(opts *bind.FilterOpts) (*VRFCoordinatorPauseFlagChangedIterator, error) - - WatchPauseFlagChanged(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorPauseFlagChanged) (event.Subscription, error) - - ParsePauseFlagChanged(log types.Log) (*VRFCoordinatorPauseFlagChanged, error) - - FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*VRFCoordinatorRandomWordsFulfilledIterator, error) - - WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error) - - ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorRandomWordsFulfilled, error) - - FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFCoordinatorRandomnessFulfillmentRequestedIterator, error) - - WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) - - ParseRandomnessFulfillmentRequested(log types.Log) (*VRFCoordinatorRandomnessFulfillmentRequested, error) - - FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*VRFCoordinatorRandomnessRedeemedIterator, error) - - WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) - - ParseRandomnessRedeemed(log types.Log) (*VRFCoordinatorRandomnessRedeemed, error) - - FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*VRFCoordinatorRandomnessRequestedIterator, error) - - WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorRandomnessRequested, requestID []*big.Int) (event.Subscription, error) - - ParseRandomnessRequested(log types.Log) (*VRFCoordinatorRandomnessRequested, error) - - FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionCanceledIterator, error) - - WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionCanceled, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorSubscriptionCanceled, error) - - FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionConsumerAddedIterator, error) - - WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionConsumerAdded, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorSubscriptionConsumerAdded, error) - - FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionConsumerRemovedIterator, error) - - WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionConsumerRemoved, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorSubscriptionConsumerRemoved, error) - - FilterSubscriptionCreated(opts *bind.FilterOpts, subId []*big.Int, owner []common.Address) (*VRFCoordinatorSubscriptionCreatedIterator, error) - - WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionCreated, subId []*big.Int, owner []common.Address) (event.Subscription, error) - - ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorSubscriptionCreated, error) - - FilterSubscriptionFunded(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionFundedIterator, error) - - WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionFunded, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorSubscriptionFunded, error) - - FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error) - - WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionOwnerTransferRequested, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorSubscriptionOwnerTransferRequested, error) - - FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []*big.Int) (*VRFCoordinatorSubscriptionOwnerTransferredIterator, error) - - WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorSubscriptionOwnerTransferred, subId []*big.Int) (event.Subscription, error) - - ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorSubscriptionOwnerTransferred, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/ocr2vrf/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ocr2vrf/generation/generated-wrapper-dependency-versions-do-not-edit.txt deleted file mode 100644 index ce0b1a09702..00000000000 --- a/core/gethwrappers/ocr2vrf/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ /dev/null @@ -1,7 +0,0 @@ -GETH_VERSION: 1.12.0 -dkg: ../../../contracts/solc/v0.8.19/DKG.abi ../../../contracts/solc/v0.8.19/DKG.bin 02549733c46e50ba393c2521e39d4ec55b6a5d9a66baf4406b1a515b20470425 -load_test_beacon_consumer: ../../../contracts/solc/v0.8.19/LoadTestBeaconVRFConsumer.abi ../../../contracts/solc/v0.8.19/LoadTestBeaconVRFConsumer.bin 7306576bc1db6c0a4f0a8a83dd4c08e3078afa73b72858f7d1eaa410d1128fd2 -vrf_beacon: ../../../contracts/solc/v0.8.19/VRFBeacon.abi ../../../contracts/solc/v0.8.19/VRFBeacon.bin 63107992adf02024afccbe77fdf973777548dcd4d9af1484c8449aca6de30f4c -vrf_beacon_consumer: ../../../contracts/solc/v0.8.19/BeaconVRFConsumer.abi ../../../contracts/solc/v0.8.19/BeaconVRFConsumer.bin 520f1c24e4d926a4eb6c9504506b55b79a35ae8cc65ee02d28309a7d5b735a53 -vrf_beacon_coordinator: ../../../contracts/solc/v0.8.15/VRFBeaconCoordinator.abi ../../../contracts/solc/v0.8.15/VRFBeaconCoordinator.bin 08da747a3488fcd318ddc0db75fd0df7c07a100b2e19061f0efcb12a7180ecde -vrf_coordinator: ../../../contracts/solc/v0.8.19/VRFCoordinator.abi ../../../contracts/solc/v0.8.19/VRFCoordinator.bin 295bec795ab8c1ef08b6b27a67bab7f06233660e8a2f389211e470cc2b58c5ea diff --git a/core/gethwrappers/ocr2vrf/go_generate.go b/core/gethwrappers/ocr2vrf/go_generate.go deleted file mode 100644 index 475bf7e8f67..00000000000 --- a/core/gethwrappers/ocr2vrf/go_generate.go +++ /dev/null @@ -1,10 +0,0 @@ -// Package gethwrappers provides tools for wrapping solidity contracts with -// golang packages, using abigen. -package gethwrappers - -// OCR2VRF - remove the _disabled tag to run these locally. -//go:generate_disabled go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/DKG.abi ../../../contracts/solc/v0.8.19/DKG.bin DKG dkg -//go:generate_disabled go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/VRFCoordinator.abi ../../../contracts/solc/v0.8.19/VRFCoordinator.bin VRFCoordinator vrf_coordinator -//go:generate_disabled go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/VRFBeacon.abi ../../../contracts/solc/v0.8.19/VRFBeacon.bin VRFBeacon vrf_beacon -//go:generate_disabled go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/BeaconVRFConsumer.abi ../../../contracts/solc/v0.8.19/BeaconVRFConsumer.bin BeaconVRFConsumer vrf_beacon_consumer -//go:generate_disabled go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/LoadTestBeaconVRFConsumer.abi ../../../contracts/solc/v0.8.19/LoadTestBeaconVRFConsumer.bin LoadTestBeaconVRFConsumer load_test_beacon_consumer diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index f911d04df40..367d6730ebf 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -66,10 +66,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -119,16 +118,15 @@ var ( DefaultP2PPeerID p2pkey.PeerID FixtureChainID = *testutils.FixtureChainID - DefaultCosmosKey = cosmoskey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) - DefaultCSAKey = csakey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) - DefaultOCRKey = ocrkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) - DefaultOCR2Key = ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed), "evm") - DefaultP2PKey = p2pkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) - DefaultSolanaKey = solkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) - DefaultStarkNetKey = starkkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) - DefaultVRFKey = vrfkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) - DefaultDKGSignKey = dkgsignkey.MustNewXXXTestingOnly(big.NewInt(KeyBigIntSeed)) - DefaultDKGEncryptKey = dkgencryptkey.MustNewXXXTestingOnly(big.NewInt(KeyBigIntSeed)) + DefaultCosmosKey = cosmoskey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) + DefaultCSAKey = csakey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) + DefaultOCRKey = ocrkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) + DefaultOCR2Key = ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed), "evm") + DefaultP2PKey = p2pkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) + DefaultSolanaKey = solkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) + DefaultStarkNetKey = starkkey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) + DefaultAptosKey = aptoskey.MustNewInsecure(keystest.NewRandReaderFromSeed(KeyBigIntSeed)) + DefaultVRFKey = vrfkey.MustNewV2XXXTestingOnly(big.NewInt(KeyBigIntSeed)) ) func init() { diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index f845d46ca8d..cbb8ebaaa04 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/flags.go b/core/internal/mocks/flags.go index 3f9e47095e6..7d38a96d924 100644 --- a/core/internal/mocks/flags.go +++ b/core/internal/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go index c1e35f41e2f..1501e36e941 100644 --- a/core/internal/mocks/flux_aggregator.go +++ b/core/internal/mocks/flux_aggregator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/internal/mocks/go_generate.go b/core/internal/mocks/go_generate.go index f3f5f0ae2ca..07a16c2b6cc 100644 --- a/core/internal/mocks/go_generate.go +++ b/core/internal/mocks/go_generate.go @@ -4,5 +4,3 @@ package mocks //go:generate mockery --quiet --srcpkg github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper --name FlagsInterface --output . --case=underscore --structname Flags --filename flags.go //go:generate mockery --quiet --srcpkg github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface --name AggregatorV3InterfaceInterface --output ../../services/vrf/mocks/ --case=underscore --structname AggregatorV3Interface --filename aggregator_v3_interface.go //go:generate mockery --quiet --srcpkg github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2 --name VRFCoordinatorV2Interface --output ../../services/vrf/mocks/ --case=underscore --structname VRFCoordinatorV2Interface --filename vrf_coordinator_v2.go -//go:generate mockery --quiet --srcpkg github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon --name VRFBeaconInterface --output ../../services/ocr2/plugins/ocr2vrf/coordinator/mocks --case=underscore --structname VRFBeaconInterface --filename vrf_beacon.go -//go:generate mockery --quiet --srcpkg github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator --name VRFCoordinatorInterface --output ../../services/ocr2/plugins/ocr2vrf/coordinator/mocks --case=underscore --structname VRFCoordinatorInterface --filename vrf_coordinator.go diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go index 81ff22d9d52..65cc7390307 100644 --- a/core/internal/mocks/prometheus_backend.go +++ b/core/internal/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/logger/logger_mock_test.go b/core/logger/logger_mock_test.go index 8d52734fe57..0c901c7eb21 100644 --- a/core/logger/logger_mock_test.go +++ b/core/logger/logger_mock_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package logger diff --git a/core/logger/mocks/logger.go b/core/logger/mocks/logger.go index 7e56bf8d22b..da881894d1a 100644 --- a/core/logger/mocks/logger.go +++ b/core/logger/mocks/logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b3ed78c4d9d..90531919c19 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -24,17 +24,15 @@ require ( github.com/prometheus/client_golang v1.17.0 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf - github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.9.0 github.com/umbracle/ethgo v0.1.3 github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 github.com/urfave/cli v1.22.14 - go.dedis.ch/kyber/v3 v3.1.0 google.golang.org/protobuf v1.33.0 k8s.io/api v0.30.0 k8s.io/apimachinery v0.30.0 @@ -278,16 +276,15 @@ require ( github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.24.3 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d // indirect - github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.8.1 // indirect + github.com/smartcontractkit/wsrpc v0.7.3 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -323,6 +320,7 @@ require ( github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect + go.dedis.ch/kyber/v3 v3.1.0 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.mongodb.org/mongo-driver v1.15.0 // indirect go.opencensus.io v0.24.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index aee685e5cd5..8528f0beb24 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -657,6 +657,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1213,32 +1214,30 @@ 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.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf h1:d9AS/K8RSVG64USb20N/U7RaPOsYPcmuLGJq7iE+caM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf/go.mod h1:L32xvCpk84Nglit64OhySPMP1tM3TTBK7Tw0qZl7Sd4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d h1:5tgMC5Gi2UAOKZ+m28W8ubjLeR0pQCAcrz6eQ0rW510= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe h1:lYyWmjheglMu0y3JmfSqs9Dm4tZO34RmbUTOtQ4CadE= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe/go.mod h1:EWvSuqIJUYXZLEHewC7WCaPylM2jyjF3Q36BZPS4MoI= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 h1:TMOoYaeSDkkI3jkCH7lKHOZaLkeDuxFTNC+XblD6M0M= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 h1:Vs6myS+bpPwb8chUY7XxveJyhvejknhOmhDTddgsK5I= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527/go.mod h1:KRK7KlAEpmORi+nJgT0vxQVWvlLEBQ6zgzXziZuKvUM= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h1:MD80ZRCTvxxJ8PBmhtrKoTnky8cVNYrCrIBLVRbrOM0= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 h1:YudTCEe/2xWdfPY/ESSiPFW4MVsrAoi2MWPwRUJ6QAA= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 h1:640M3TP06nBckEVqRZljcG/7AJlBxJ6vLXTHy6xCtwE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba h1:YNSlhK5mobyAaw02LPGgIEuS3lXyCTXcc6oaV2L6uUI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU= -github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 h1:LQmRsrzzaYYN3wEU1l5tWiccznhvbyGnu2N+wHSXZAo= -github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e h1:9ypZ/8aW8Vm497i1gXHcT96oNLiu88jbg9QdX+IUE3E= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= -github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= +github.com/smartcontractkit/wsrpc v0.7.3 h1:CKYZfawZShZGfvsQep1F9oBansnFk9ByZPCdTMpLphw= +github.com/smartcontractkit/wsrpc v0.7.3/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1414,7 +1413,6 @@ go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0= go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= -go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= @@ -1479,6 +1477,7 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1715,7 +1714,6 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/core/scripts/ocr2vrf/main.go b/core/scripts/ocr2vrf/main.go deleted file mode 100644 index e7da4589951..00000000000 --- a/core/scripts/ocr2vrf/main.go +++ /dev/null @@ -1,455 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "math/big" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/shopspring/decimal" - - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" -) - -type commonSetConfigArgs struct { - onchainPubKeys string - offchainPubKeys string - configPubKeys string - peerIDs string - transmitters string - schedule string - f uint - deltaProgress time.Duration - deltaResend time.Duration - deltaRound time.Duration - deltaGrace time.Duration - deltaStage time.Duration - maxRounds uint8 - maxDurationQuery time.Duration - maxDurationObservation time.Duration - maxDurationReport time.Duration - maxDurationAccept time.Duration - maxDurationTransmit time.Duration -} - -type dkgSetConfigArgs struct { - commonSetConfigArgs - dkgEncryptionPubKeys string - dkgSigningPubKeys string - keyID string -} - -type vrfBeaconSetConfigArgs struct { - commonSetConfigArgs - confDelays string - coordinatorConfig ocr2vrftypes.CoordinatorConfig -} - -func main() { - e := helpers.SetupEnv(false) - - switch os.Args[1] { - case "dkg-deploy": - deployDKG(e) - case "coordinator-deploy": - cmd := flag.NewFlagSet("coordinator-deploy", flag.ExitOnError) - beaconPeriodBlocks := cmd.Int64("beacon-period-blocks", 1, "beacon period in number of blocks") - linkAddress := cmd.String("link-address", "", "link contract address") - linkEthFeed := cmd.String("link-eth-feed", "", "link/eth feed address") - helpers.ParseArgs(cmd, os.Args[2:], "beacon-period-blocks", "link-address", "link-eth-feed") - deployVRFCoordinator(e, big.NewInt(*beaconPeriodBlocks), *linkAddress, *linkEthFeed) - case "beacon-deploy": - cmd := flag.NewFlagSet("beacon-deploy", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "coordinator contract address") - linkAddress := cmd.String("link-address", "", "link contract address") - dkgAddress := cmd.String("dkg-address", "", "dkg contract address") - keyID := cmd.String("key-id", "", "key ID") - helpers.ParseArgs(cmd, os.Args[2:], "beacon-deploy", "coordinator-address", "link-address", "dkg-address", "key-id") - deployVRFBeacon(e, *coordinatorAddress, *linkAddress, *dkgAddress, *keyID) - case "dkg-add-client": - cmd := flag.NewFlagSet("dkg-add-client", flag.ExitOnError) - dkgAddress := cmd.String("dkg-address", "", "DKG contract address") - keyID := cmd.String("key-id", "", "key ID") - clientAddress := cmd.String("client-address", "", "client address") - helpers.ParseArgs(cmd, os.Args[2:], "dkg-address", "key-id", "client-address") - addClientToDKG(e, *dkgAddress, *keyID, *clientAddress) - case "dkg-remove-client": - cmd := flag.NewFlagSet("dkg-add-client", flag.ExitOnError) - dkgAddress := cmd.String("dkg-address", "", "DKG contract address") - keyID := cmd.String("key-id", "", "key ID") - clientAddress := cmd.String("client-address", "", "client address") - helpers.ParseArgs(cmd, os.Args[2:], "dkg-address", "key-id", "client-address") - removeClientFromDKG(e, *dkgAddress, *keyID, *clientAddress) - case "dkg-set-config": - cmd := flag.NewFlagSet("dkg-set-config", flag.ExitOnError) - dkgAddress := cmd.String("dkg-address", "", "DKG contract address") - keyID := cmd.String("key-id", "", "key ID") - onchainPubKeys := cmd.String("onchain-pub-keys", "", "comma-separated list of OCR on-chain pubkeys") - offchainPubKeys := cmd.String("offchain-pub-keys", "", "comma-separated list of OCR off-chain pubkeys") - configPubKeys := cmd.String("config-pub-keys", "", "comma-separated list of OCR config pubkeys") - peerIDs := cmd.String("peer-ids", "", "comma-separated list of peer IDs") - transmitters := cmd.String("transmitters", "", "comma-separated list transmitters") - dkgEncryptionPubKeys := cmd.String("dkg-encryption-pub-keys", "", "comma-separated list of DKG encryption pubkeys") - dkgSigningPubKeys := cmd.String("dkg-signing-pub-keys", "", "comma-separated list of DKG signing pubkeys") - schedule := cmd.String("schedule", "", "comma-separted list of transmission schedule") - f := cmd.Uint("f", 1, "number of faulty oracles") - deltaProgress := cmd.Duration("delta-progress", 30*time.Second, "duration of delta progress") - deltaResend := cmd.Duration("delta-resend", 10*time.Second, "duration of delta resend") - deltaRound := cmd.Duration("delta-round", 10*time.Second, "duration of delta round") - deltaGrace := cmd.Duration("delta-grace", 20*time.Second, "duration of delta grace") - deltaStage := cmd.Duration("delta-stage", 20*time.Second, "duration of delta stage") - maxRounds := cmd.Uint("max-rounds", 3, "maximum number of rounds") - maxDurationQuery := cmd.Duration("max-duration-query", 10*time.Millisecond, "maximum duration of query") - maxDurationObservation := cmd.Duration("max-duration-observation", 10*time.Second, "maximum duration of observation method") - maxDurationReport := cmd.Duration("max-duration-report", 10*time.Second, "maximum duration of report method") - maxDurationAccept := cmd.Duration("max-duration-accept", 10*time.Millisecond, "maximum duration of shouldAcceptFinalizedReport method") - maxDurationTransmit := cmd.Duration("max-duration-transmit", 1*time.Second, "maximum duration of shouldTransmitAcceptedReport method") - - helpers.ParseArgs(cmd, - os.Args[2:], - "dkg-address", - "key-id", - "onchain-pub-keys", - "offchain-pub-keys", - "config-pub-keys", - "peer-ids", - "transmitters", - "dkg-encryption-pub-keys", - "dkg-signing-pub-keys", - "schedule") - - commands := dkgSetConfigArgs{ - commonSetConfigArgs: commonSetConfigArgs{ - onchainPubKeys: *onchainPubKeys, - offchainPubKeys: *offchainPubKeys, - configPubKeys: *configPubKeys, - peerIDs: *peerIDs, - transmitters: *transmitters, - schedule: *schedule, - f: *f, - deltaProgress: *deltaProgress, - deltaResend: *deltaResend, - deltaRound: *deltaRound, - deltaGrace: *deltaGrace, - deltaStage: *deltaStage, - maxRounds: uint8(*maxRounds), - maxDurationQuery: *maxDurationQuery, - maxDurationObservation: *maxDurationObservation, - maxDurationReport: *maxDurationReport, - maxDurationAccept: *maxDurationAccept, - maxDurationTransmit: *maxDurationTransmit, - }, - dkgEncryptionPubKeys: *dkgEncryptionPubKeys, - dkgSigningPubKeys: *dkgSigningPubKeys, - keyID: *keyID, - } - - setDKGConfig(e, *dkgAddress, commands) - case "beacon-set-config": - cmd := flag.NewFlagSet("beacon-set-config", flag.ExitOnError) - beaconAddress := cmd.String("beacon-address", "", "VRF beacon contract address") - confDelays := cmd.String("conf-delays", "1,2,3,4,5,6,7,8", "comma-separted list of 8 confirmation delays") - onchainPubKeys := cmd.String("onchain-pub-keys", "", "comma-separated list of OCR on-chain pubkeys") - offchainPubKeys := cmd.String("offchain-pub-keys", "", "comma-separated list of OCR off-chain pubkeys") - configPubKeys := cmd.String("config-pub-keys", "", "comma-separated list of OCR config pubkeys") - peerIDs := cmd.String("peer-ids", "", "comma-separated list of peer IDs") - transmitters := cmd.String("transmitters", "", "comma-separated list transmitters") - schedule := cmd.String("schedule", "", "comma-separted list of transmission schedule") - f := cmd.Uint("f", 1, "number of faulty oracles") - // TODO: Adjust default delta* and maxDuration* values below after benchmarking latency - deltaProgress := cmd.Duration("delta-progress", 30*time.Second, "duration of delta progress") - deltaResend := cmd.Duration("delta-resend", 10*time.Second, "duration of delta resend") - deltaRound := cmd.Duration("delta-round", 10*time.Second, "duration of delta round") - deltaGrace := cmd.Duration("delta-grace", 20*time.Second, "duration of delta grace") - deltaStage := cmd.Duration("delta-stage", 20*time.Second, "duration of delta stage") - cacheEvictionWindowSeconds := cmd.Int64("cache-eviction-window", 60, "cache eviction window, in seconds") - batchGasLimit := cmd.Int64("batch-gas-limit", 5_000_000, "batch gas limit") - coordinatorOverhead := cmd.Int64("coordinator-overhead", 50_000, "coordinator overhead") - callbackOverhead := cmd.Int64("callback-overhead", 50_000, "callback overhead") - blockGasOverhead := cmd.Int64("block-gas-overhead", 50_000, "block gas overhead") - lookbackBlocks := cmd.Uint64("lookback-blocks", 1000, "lookback blocks") - maxRounds := cmd.Uint("max-rounds", 3, "maximum number of rounds") - maxDurationQuery := cmd.Duration("max-duration-query", 10*time.Millisecond, "maximum duration of query") - maxDurationObservation := cmd.Duration("max-duration-observation", 10*time.Second, "maximum duration of observation method") - maxDurationReport := cmd.Duration("max-duration-report", 10*time.Second, "maximum duration of report method") - maxDurationAccept := cmd.Duration("max-duration-accept", 5*time.Second, "maximum duration of shouldAcceptFinalizedReport method") - maxDurationTransmit := cmd.Duration("max-duration-transmit", 1*time.Second, "maximum duration of shouldTransmitAcceptedReport method") - - helpers.ParseArgs(cmd, - os.Args[2:], - "beacon-address", - "onchain-pub-keys", - "offchain-pub-keys", - "config-pub-keys", - "peer-ids", - "transmitters", - "schedule") - - commands := vrfBeaconSetConfigArgs{ - commonSetConfigArgs: commonSetConfigArgs{ - onchainPubKeys: *onchainPubKeys, - offchainPubKeys: *offchainPubKeys, - configPubKeys: *configPubKeys, - peerIDs: *peerIDs, - transmitters: *transmitters, - schedule: *schedule, - f: *f, - deltaProgress: *deltaProgress, - deltaResend: *deltaResend, - deltaRound: *deltaRound, - deltaGrace: *deltaGrace, - deltaStage: *deltaStage, - maxRounds: uint8(*maxRounds), - maxDurationQuery: *maxDurationQuery, - maxDurationObservation: *maxDurationObservation, - maxDurationReport: *maxDurationReport, - maxDurationAccept: *maxDurationAccept, - maxDurationTransmit: *maxDurationTransmit, - }, - confDelays: *confDelays, - coordinatorConfig: ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: *cacheEvictionWindowSeconds, - BatchGasLimit: *batchGasLimit, - CoordinatorOverhead: *coordinatorOverhead, - CallbackOverhead: *callbackOverhead, - BlockGasOverhead: *blockGasOverhead, - LookbackBlocks: *lookbackBlocks, - }, - } - - commands.setVRFBeaconConfig(e, *beaconAddress) - case "coordinator-set-producer": - cmd := flag.NewFlagSet("coordinator-set-producer", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - beaconAddress := cmd.String("beacon-address", "", "VRF beacon contract address") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "beacon-address") - setProducer(e, *coordinatorAddress, *beaconAddress) - case "coordinator-request-randomness": - cmd := flag.NewFlagSet("coordinator-request-randomness", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - numWords := cmd.Uint("num-words", 1, "number of words to request") - subID := cmd.String("sub-id", "", "subscription ID") - confDelay := cmd.Int64("conf-delay", 1, "confirmation delay") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "sub-id") - requestRandomness( - e, - *coordinatorAddress, - uint16(*numWords), - decimal.RequireFromString(*subID).BigInt(), - big.NewInt(*confDelay)) - case "coordinator-redeem-randomness": - cmd := flag.NewFlagSet("coordinator-redeem-randomness", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - subID := cmd.String("sub-id", "", "subscription ID") - requestID := cmd.Int64("request-id", 0, "request ID") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "sub-id", "request-id") - redeemRandomness( - e, - *coordinatorAddress, - decimal.RequireFromString(*subID).BigInt(), - big.NewInt(*requestID)) - case "beacon-info": - cmd := flag.NewFlagSet("beacon-info", flag.ExitOnError) - beaconAddress := cmd.String("beacon-address", "", "VRF beacon contract address") - helpers.ParseArgs(cmd, os.Args[2:], "beacon-address") - beacon := newVRFBeacon(common.HexToAddress(*beaconAddress), e.Ec) - keyID, err := beacon.SKeyID(nil) - helpers.PanicErr(err) - fmt.Println("beacon key id:", hexutil.Encode(keyID[:])) - keyHash, err := beacon.SProvingKeyHash(nil) - helpers.PanicErr(err) - fmt.Println("beacon proving key hash:", hexutil.Encode(keyHash[:])) - case "coordinator-create-sub": - cmd := flag.NewFlagSet("coordinator-create-sub", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address") - createSubscription(e, *coordinatorAddress) - case "coordinator-add-consumer": - cmd := flag.NewFlagSet("coordinator-add-consumer", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - consumerAddress := cmd.String("consumer-address", "", "VRF consumer contract address") - subId := cmd.String("sub-id", "", "subscription ID") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "consumer-address") - addConsumer(e, *coordinatorAddress, *consumerAddress, decimal.RequireFromString(*subId).BigInt()) - case "coordinator-get-sub": - cmd := flag.NewFlagSet("coordinator-get-sub", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - subId := cmd.String("sub-id", "", "subscription ID") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address") - sub := getSubscription(e, *coordinatorAddress, decimal.RequireFromString(*subId).BigInt()) - fmt.Println("subscription ID:", *subId) - fmt.Println("balance:", sub.Balance) - fmt.Println("consumers:", sub.Consumers) - fmt.Println("owner:", sub.Owner) - case "link-balance": - cmd := flag.NewFlagSet("link-balance", flag.ExitOnError) - linkAddress := cmd.String("link-address", "", "link address") - helpers.ParseArgs(cmd, os.Args[2:], "link-address") - - l, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) - helpers.PanicErr(err) - - bal, err := l.BalanceOf(nil, e.Owner.From) - helpers.PanicErr(err) - fmt.Println("link balance of", e.Owner.From, "is", assets.NewWei(bal).String()) - case "get-balances": - cmd := flag.NewFlagSet("get-balances", flag.ExitOnError) - addresses := cmd.String("addresses", "", "comma-separated list of addresses") - helpers.ParseArgs(cmd, os.Args[2:], "addresses") - - for _, account := range strings.Split(*addresses, ",") { - bal, err := e.Ec.BalanceAt(context.Background(), common.HexToAddress(account), nil) - helpers.PanicErr(err) - - fmt.Println("ETH balance of", account, "is", assets.NewWei(bal).String()) - } - case "coordinator-fund-sub": - cmd := flag.NewFlagSet("coordinator-fund-sub", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - linkAddress := cmd.String("link-address", "", "link-address") - fundingAmount := cmd.String("funding-amount", "5e18", "funding amount in juels. can use scientific notation, e.g 10e18 for 10 LINK") // 5 LINK - subID := cmd.String("sub-id", "", "subscription ID") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "link-address") - eoaFundSubscription(e, *coordinatorAddress, *linkAddress, decimal.RequireFromString(*fundingAmount).BigInt(), decimal.RequireFromString(*subID).BigInt()) - case "beacon-set-payees": - cmd := flag.NewFlagSet("beacon-set-payees", flag.ExitOnError) - beaconAddress := cmd.String("beacon-address", "", "VRF beacon contract address") - transmitters := cmd.String("transmitters", "", "comma-separated list of transmitters") - payees := cmd.String("payees", "", "comma-separated list of payees") - helpers.ParseArgs(cmd, os.Args[2:], "beacon-address", "transmitters", "payees") - setPayees(e, *beaconAddress, helpers.ParseAddressSlice(*transmitters), helpers.ParseAddressSlice(*payees)) - case "consumer-deploy": - cmd := flag.NewFlagSet("consumer-deploy", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator address") - shouldFail := cmd.Bool("should-fail", false, "shouldFail flag") - beaconPeriodBlocks := cmd.Int64("beacon-period-blocks", 1, "beacon period in number of blocks") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "beacon-period-blocks") - deployVRFBeaconCoordinatorConsumer(e, *coordinatorAddress, *shouldFail, big.NewInt(*beaconPeriodBlocks)) - case "consumer-request-randomness": - cmd := flag.NewFlagSet("consumer-request-randomness", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF coordinator consumer address") - numWords := cmd.Uint("num-words", 1, "number of words to request") - subID := cmd.String("sub-id", "", "subscription ID") - confDelay := cmd.Int64("conf-delay", 1, "confirmation delay") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address", "sub-id") - requestRandomnessFromConsumer(e, *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), big.NewInt(*confDelay)) - case "consumer-redeem-randomness": - cmd := flag.NewFlagSet("consumer-redeem-randomness", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF coordinator consumer address") - subID := cmd.String("sub-id", "", "subscription ID") - requestID := cmd.String("request-id", "0", "request ID") - numWords := cmd.Int64("num-words", 1, "number of words to print after redeeming") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address", "request-id") - reqIdInt := decimal.RequireFromString(*requestID).BigInt() - redeemRandomnessFromConsumer(e, *consumerAddress, decimal.RequireFromString(*subID).BigInt(), reqIdInt, *numWords) - case "consumer-request-callback": - cmd := flag.NewFlagSet("consumer-request-callback", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF coordinator consumer address") - numWords := cmd.Uint("num-words", 1, "number of words to request") - subID := cmd.String("sub-id", "", "subscription ID") - confDelay := cmd.Int64("conf-delay", 1, "confirmation delay") - callbackGasLimit := cmd.Uint("cb-gas-limit", 100_000, "callback gas limit") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address") - requestRandomnessCallback( - e, - *consumerAddress, - uint16(*numWords), - decimal.RequireFromString(*subID).BigInt(), - big.NewInt(*confDelay), - uint32(*callbackGasLimit), - nil, // test consumer doesn't use any args - ) - case "consumer-read-randomness": - cmd := flag.NewFlagSet("consumer-read-randomness", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF coordinator consumer address") - requestID := cmd.String("request-id", "", "VRF request ID") - numWords := cmd.Int("num-words", 1, "number of words to fetch") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address") - readRandomness(e, *consumerAddress, decimal.RequireFromString(*requestID).BigInt(), *numWords) - case "consumer-request-callback-batch": - cmd := flag.NewFlagSet("consumer-request-callback", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF beacon consumer address") - numWords := cmd.Uint("num-words", 1, "number of words to request") - subID := cmd.String("sub-id", "", "subscription ID") - confDelay := cmd.Int64("conf-delay", 1, "confirmation delay") - batchSize := cmd.Int64("batch-size", 1, "batch size") - callbackGasLimit := cmd.Uint("cb-gas-limit", 200_000, "callback gas limit") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address") - requestRandomnessCallbackBatch( - e, - *consumerAddress, - uint16(*numWords), - decimal.RequireFromString(*subID).BigInt(), - big.NewInt(*confDelay), - uint32(*callbackGasLimit), - nil, // test consumer doesn't use any args, - big.NewInt(*batchSize), - ) - case "consumer-request-callback-batch-load-test": - cmd := flag.NewFlagSet("consumer-request-callback-load-test", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "VRF beacon batch consumer address") - numWords := cmd.Uint("num-words", 1, "number of words to request") - subID := cmd.String("sub-id", "", "subscription ID") - confDelay := cmd.Int64("conf-delay", 1, "confirmation delay") - batchSize := cmd.Int64("batch-size", 1, "batch size") - batchCount := cmd.Int64("batch-count", 1, "number of batches to run") - callbackGasLimit := cmd.Uint("cb-gas-limit", 200_000, "callback gas limit") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address") - - for i := int64(0); i < *batchCount; i++ { - requestRandomnessCallbackBatch( - e, - *consumerAddress, - uint16(*numWords), - decimal.RequireFromString(*subID).BigInt(), - big.NewInt(*confDelay), - uint32(*callbackGasLimit), - nil, // test consumer doesn't use any args, - big.NewInt(*batchSize), - ) - } - case "deploy-load-test-consumer": - cmd := flag.NewFlagSet("deploy-load-test-consumer", flag.ExitOnError) - coordinatorAddress := cmd.String("coordinator-address", "", "coordinator address") - beaconPeriodBlocks := cmd.Int64("beacon-period-blocks", 1, "beacon period in number of blocks") - helpers.ParseArgs(cmd, os.Args[2:], "coordinator-address", "beacon-period-blocks") - - deployLoadTestVRFBeaconCoordinatorConsumer(e, *coordinatorAddress, false, big.NewInt(*beaconPeriodBlocks)) - case "get-load-test-results": - cmd := flag.NewFlagSet("get-load-test-results", flag.ExitOnError) - consumerAddress := cmd.String("consumer-address", "", "Load test contract address") - helpers.ParseArgs(cmd, os.Args[2:], "consumer-address") - - printLoadtestResults(e, *consumerAddress) - case "verify-beacon-randomness": - cmd := flag.NewFlagSet("verify-randomness", flag.ExitOnError) - dkgAddress := cmd.String("dkg-address", "", "DKG contract address") - beaconAddress := cmd.String("beacon-address", "", "VRF beacon contract address") - coordinatorAddress := cmd.String("coordinator-address", "", "VRF coordinator contract address") - height := cmd.Uint64("height", 0, "block height of VRF beacon output") - confDelay := cmd.Uint64("conf-delay", 1, "confirmation delay of VRF beacon output") - searchWindow := cmd.Uint64("search-window", 200, "search space size for beacon transmission. Number of blocks after beacon height") - helpers.ParseArgs(cmd, os.Args[2:], "dkg-address", "coordinator-address", "beacon-address", "height", "conf-delay") - - verifyBeaconRandomness(e, *dkgAddress, *beaconAddress, *coordinatorAddress, *height, *confDelay, *searchWindow) - case "dkg-setup": - setupDKGNodes(e) - case "ocr2vrf-setup": - setupOCR2VRFNodes(e) - case "ocr2vrf-setup-infra-forwarder": - setupOCR2VRFNodesForInfraWithForwarder(e) - case "ocr2vrf-fund-nodes": - fundOCR2VRFNodes(e) - default: - panic("unrecognized subcommand: " + os.Args[1]) - } -} diff --git a/core/scripts/ocr2vrf/readiness/main.go b/core/scripts/ocr2vrf/readiness/main.go deleted file mode 100644 index 9b43009d2f2..00000000000 --- a/core/scripts/ocr2vrf/readiness/main.go +++ /dev/null @@ -1,214 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "io" - "os" - "strings" - - "github.com/urfave/cli" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - clcmd "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { - prompter := clcmd.NewTerminalPrompter() - client := &clcmd.Shell{ - Renderer: clcmd.RendererJSON{Writer: writer}, - AppFactory: clcmd.ChainlinkAppFactory{}, - KeyStoreAuthenticator: clcmd.TerminalKeyStoreAuthenticator{Prompter: prompter}, - FallbackAPIInitializer: clcmd.NewPromptingAPIInitializer(prompter), - Runner: clcmd.ChainlinkRunner{}, - PromptingSessionRequestBuilder: clcmd.NewPromptingSessionRequestBuilder(prompter), - ChangePasswordPrompter: clcmd.NewChangePasswordPrompter(), - PasswordPrompter: clcmd.NewPasswordPrompter(), - } - app := clcmd.NewApp(client) - fs := flag.NewFlagSet("blah", flag.ContinueOnError) - fs.Bool("json", true, "") - fs.String("remote-node-url", remoteNodeURL, "") - helpers.PanicErr(app.Before(cli.NewContext(nil, fs, nil))) - // overwrite renderer since it's set to stdout after Before() is called - client.Renderer = clcmd.RendererJSON{Writer: writer} - return client, app -} - -var ( - remoteNodeURLs = flag.String("remote-node-urls", "", "remote node URL") - checkMarkEmoji = "✅" - xEmoji = "❌" - infoEmoji = "ℹ️" -) - -type ocr2Bundle struct { - ID string `json:"id"` - ChainType string `json:"chainType"` - OnchainPublicKey string `json:"onchainPublicKey"` - OffchainPublicKey string `json:"offchainPublicKey"` - ConfigPublicKey string `json:"configPublicKey"` -} - -func main() { - flag.Parse() - - if remoteNodeURLs == nil { - fmt.Println("flag -remote-node-urls required") - os.Exit(1) - } - - urls := strings.Split(*remoteNodeURLs, ",") - var ( - allDKGSignKeys []string - allDKGEncryptKeys []string - allOCR2KeyIDs []string - allOCR2OffchainPubkeys []string - allOCR2OnchainPubkeys []string - allOCR2ConfigPubkeys []string - allETHKeys []string - allPeerIDs []string - ) - for _, remoteNodeURL := range urls { - output := &bytes.Buffer{} - client, app := newApp(remoteNodeURL, output) - - // login first to establish the session - fmt.Println("logging in to:", remoteNodeURL) - loginFs := flag.NewFlagSet("test", flag.ContinueOnError) - loginFs.String("file", "", "") - loginFs.Bool("bypass-version-check", true, "") - loginCtx := cli.NewContext(app, loginFs, nil) - err := client.RemoteLogin(loginCtx) - helpers.PanicErr(err) - output.Reset() - fmt.Println() - - // check for DKG signing keys - err = clcmd.NewDKGSignKeysClient(client).ListKeys(&cli.Context{ - App: app, - }) - helpers.PanicErr(err) - var dkgSignKeys []presenters.DKGSignKeyResource - helpers.PanicErr(json.Unmarshal(output.Bytes(), &dkgSignKeys)) - switch len(dkgSignKeys) { - case 1: - fmt.Println(checkMarkEmoji, "found 1 DKG sign key on", remoteNodeURL) - case 0: - fmt.Println(xEmoji, "did not find any DKG sign keys on", remoteNodeURL, ", please create one") - default: - fmt.Println(infoEmoji, "found more than 1 DKG sign key on", remoteNodeURL, ", consider removing all but one") - } - output.Reset() - fmt.Println() - - // check for DKG encryption keys - err = clcmd.NewDKGEncryptKeysClient(client).ListKeys(&cli.Context{ - App: app, - }) - helpers.PanicErr(err) - var dkgEncryptKeys []presenters.DKGEncryptKeyResource - helpers.PanicErr(json.Unmarshal(output.Bytes(), &dkgEncryptKeys)) - switch len(dkgEncryptKeys) { - case 1: - fmt.Println(checkMarkEmoji, "found 1 DKG encrypt key on", remoteNodeURL) - case 0: - fmt.Println(xEmoji, "did not find any DKG encrypt keys on", remoteNodeURL, ", please create one") - default: - fmt.Println(infoEmoji, "found more than 1 DKG encrypt key on", remoteNodeURL, ", consider removing all but one") - } - output.Reset() - fmt.Println() - - // check for OCR2 keys - err = client.ListOCR2KeyBundles(&cli.Context{ - App: app, - }) - helpers.PanicErr(err) - var ocr2Keys []ocr2Bundle - helpers.PanicErr(json.Unmarshal(output.Bytes(), &ocr2Keys)) - ethBundle := func() *ocr2Bundle { - for _, b := range ocr2Keys { - if b.ChainType == "evm" { - return &b - } - } - return nil - }() - if ethBundle != nil { - fmt.Println(checkMarkEmoji, "found ocr evm key bundle on", remoteNodeURL) - } else { - fmt.Println(xEmoji, "did not find ocr evm key bundle on", remoteNodeURL, ", please create one") - } - output.Reset() - fmt.Println() - - // check for ETH keys - err = client.ListETHKeys(&cli.Context{ - App: app, - }) - helpers.PanicErr(err) - var ethKeys []presenters.ETHKeyResource - helpers.PanicErr(json.Unmarshal(output.Bytes(), ðKeys)) - switch { - case len(ethKeys) >= 5: - fmt.Println(checkMarkEmoji, "found", len(ethKeys), "eth keys on", remoteNodeURL) - case len(ethKeys) < 5: - fmt.Println(xEmoji, "found only", len(ethKeys), "eth keys on", remoteNodeURL, ", consider creating more") - } - output.Reset() - fmt.Println() - - // check for peer ids - err = client.ListP2PKeys(&cli.Context{ - App: app, - }) - helpers.PanicErr(err) - var p2pKeys []presenters.P2PKeyResource - helpers.PanicErr(json.Unmarshal(output.Bytes(), &p2pKeys)) - switch len(p2pKeys) { - case 1: - fmt.Println(checkMarkEmoji, "found P2P key on", remoteNodeURL) - case 0: - fmt.Println(xEmoji, "no P2P keys found on", remoteNodeURL, ", please create one") - default: - fmt.Println(infoEmoji, "found", len(p2pKeys), "P2P keys on", remoteNodeURL, ", consider removing all but one") - } - output.Reset() - fmt.Println() - - for _, dkgSign := range dkgSignKeys { - allDKGSignKeys = append(allDKGSignKeys, dkgSign.PublicKey) - } - for _, dkgEncrypt := range dkgEncryptKeys { - allDKGEncryptKeys = append(allDKGEncryptKeys, dkgEncrypt.PublicKey) - } - for _, ocr2Bundle := range ocr2Keys { - if ocr2Bundle.ChainType == "evm" { - allOCR2KeyIDs = append(allOCR2KeyIDs, ocr2Bundle.ID) - allOCR2ConfigPubkeys = append(allOCR2ConfigPubkeys, strings.TrimPrefix(ocr2Bundle.ConfigPublicKey, "ocr2cfg_evm_")) - allOCR2OffchainPubkeys = append(allOCR2OffchainPubkeys, strings.TrimPrefix(ocr2Bundle.OffchainPublicKey, "ocr2off_evm_")) - allOCR2OnchainPubkeys = append(allOCR2OnchainPubkeys, strings.TrimPrefix(ocr2Bundle.OnchainPublicKey, "ocr2on_evm_")) - } - } - for _, ethKey := range ethKeys { - allETHKeys = append(allETHKeys, ethKey.Address) - } - for _, peerKey := range p2pKeys { - allPeerIDs = append(allPeerIDs, strings.TrimPrefix(peerKey.PeerID, "p2p_")) - } - } - - fmt.Println("------------- NODE INFORMATION -------------") - fmt.Println("DKG sign keys:", strings.Join(allDKGSignKeys, ",")) - fmt.Println("DKG encrypt keys:", strings.Join(allDKGEncryptKeys, ",")) - fmt.Println("OCR2 key IDs:", strings.Join(allOCR2KeyIDs, ",")) - fmt.Println("OCR2 config public keys:", strings.Join(allOCR2ConfigPubkeys, ",")) - fmt.Println("OCR2 onchain public keys:", strings.Join(allOCR2OnchainPubkeys, ",")) - fmt.Println("OCR2 offchain public keys:", strings.Join(allOCR2OffchainPubkeys, ",")) - fmt.Println("ETH addresses:", strings.Join(allETHKeys, ",")) - fmt.Println("Peer IDs:", strings.Join(allPeerIDs, ",")) -} diff --git a/core/scripts/ocr2vrf/setup_dkg.go b/core/scripts/ocr2vrf/setup_dkg.go deleted file mode 100644 index 834e9177f21..00000000000 --- a/core/scripts/ocr2vrf/setup_dkg.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "math/big" - "os" - "strings" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" -) - -func setupDKGNodes(e helpers.Environment) { - // Websocket URL & HTTP url required. - wsUrl := os.Getenv("ETH_URL") - httpUrl := os.Getenv("ETH_HTTP_URL") - if len(wsUrl) == 0 || len(httpUrl) == 0 { - fmt.Println("ETH_URL & ETH_HTTP_URL are required for this script.") - os.Exit(1) - } - - cmd := flag.NewFlagSet("dkg-setup", flag.ExitOnError) - keyID := cmd.String("key-id", "aee00d81f822f882b6fe28489822f59ebb21ea95c0ae21d9f67c0239461148fc", "key ID") - apiFile := cmd.String("api", "../../../tools/secrets/apicredentials", "api credentials file") - passwordFile := cmd.String("password", "../../../tools/secrets/password.txt", "password file") - databasePrefix := cmd.String("database-prefix", "postgres://postgres:postgres_password_padded_for_security@localhost:5432/dkg-test", "database prefix") - databaseSuffixes := cmd.String("database-suffixes", "sslmode=disable", "database parameters to be added") - nodeCount := cmd.Int("node-count", 6, "number of nodes") - fundingAmount := cmd.Int64("funding-amount", 10000000000000000, "amount to fund nodes") // .1 ETH - helpers.ParseArgs(cmd, os.Args[2:]) - - if *nodeCount < 6 { - fmt.Println("Node count too low for DKG job, need at least 6.") - os.Exit(1) - } - - //Deploy DKG contract. - // uncomment for faster txs - // e.Owner.GasPrice = e.Owner.GasPrice.Mul(e.Owner.GasPrice, big.NewInt(2)) - dkgAddress := deployDKG(e).String() - - // Initialize dkg-set-config arguments. - onChainPublicKeys := []string{} - offChainPublicKeys := []string{} - configPublicKeys := []string{} - peerIDs := []string{} - transmitters := []string{} - dkgEncrypters := []string{} - dkgSigners := []string{} - - // Iterate through all nodes and create jobs. - for i := 0; i < *nodeCount; i++ { - flagSet := flag.NewFlagSet("run-dkg-job-creation", flag.ExitOnError) - flagSet.String("api", *apiFile, "api file") - flagSet.String("password", *passwordFile, "password file") - flagSet.String("bootstrapPort", fmt.Sprintf("%d", 8000), "port of bootstrap") - flagSet.String("job-type", string(jobTypeDKG), "the job type") - flagSet.String("keyID", *keyID, "") - flagSet.String("contractID", dkgAddress, "the contract address of the DKG") - flagSet.Int64("chainID", e.ChainID, "the chain ID") - flagSet.Bool("dangerWillRobinson", true, "for resetting databases") - flagSet.Bool("isBootstrapper", i == 0, "is first node") - bootstrapperPeerID := "" - if len(peerIDs) != 0 { - bootstrapperPeerID = peerIDs[0] - } - flagSet.String("bootstrapperPeerID", bootstrapperPeerID, "peerID of first node") - - // Setup DKG node. - payload := SetupNode(e, flagSet, i, *databasePrefix, *databaseSuffixes, false, true, wsUrl, httpUrl) - - // Append arguments for dkg-set-config command. - onChainPublicKeys = append(onChainPublicKeys, payload.OnChainPublicKey) - offChainPublicKeys = append(offChainPublicKeys, payload.OffChainPublicKey) - configPublicKeys = append(configPublicKeys, payload.ConfigPublicKey) - peerIDs = append(peerIDs, payload.PeerID) - transmitters = append(transmitters, payload.Transmitter) - dkgEncrypters = append(dkgEncrypters, payload.DkgEncrypt) - dkgSigners = append(dkgSigners, payload.DkgSign) - } - - // Fund transmitters with funding amount. - helpers.FundNodes(e, transmitters, big.NewInt(*fundingAmount)) - - // Construct and print dkg-set-config command. - fmt.Println("Generated setConfig Command:") - command := fmt.Sprintf( - "go run . dkg-set-config --dkg-address %s -key-id %s -onchain-pub-keys %s -offchain-pub-keys %s -config-pub-keys %s -peer-ids %s -transmitters %s -dkg-encryption-pub-keys %s -dkg-signing-pub-keys %s -schedule 1,1,1,1,1", - dkgAddress, - *keyID, - strings.Join(onChainPublicKeys[1:], ","), - strings.Join(offChainPublicKeys[1:], ","), - strings.Join(configPublicKeys[1:], ","), - strings.Join(peerIDs[1:], ","), - strings.Join(transmitters[1:], ","), - strings.Join(dkgEncrypters[1:], ","), - strings.Join(dkgSigners[1:], ","), - ) - - fmt.Println(command) -} diff --git a/core/scripts/ocr2vrf/setup_ocr2vrf.go b/core/scripts/ocr2vrf/setup_ocr2vrf.go deleted file mode 100644 index 35d529b0262..00000000000 --- a/core/scripts/ocr2vrf/setup_ocr2vrf.go +++ /dev/null @@ -1,572 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "math/big" - "os" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/shopspring/decimal" - "github.com/urfave/cli" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/cmd" -) - -type jobType string - -const ( - jobTypeDKG jobType = "DKG" - jobTypeOCR2VRF jobType = "OCR2VRF" -) - -func fundOCR2VRFNodes(e helpers.Environment) { - fs := flag.NewFlagSet("ocr2vrf-setup", flag.ExitOnError) - ethSendingKeysString := fs.String("eth-sending-keys", "", "eth sending keys") - fundingAmount := fs.String("funding-amount", "1e18", "funding amount in wei. can use scientific notation, e.g 10e18 for 10 ether") // 1 ETH - helpers.ParseArgs(fs, os.Args[2:], "eth-sending-keys") - - flatSendingKeys := strings.Split(*ethSendingKeysString, ",") - helpers.FundNodes(e, flatSendingKeys, decimal.RequireFromString(*fundingAmount).BigInt()) -} - -func setupOCR2VRFNodes(e helpers.Environment) { - // Websocket URL & HTTP url required. - wsUrl := os.Getenv("ETH_URL") - httpUrl := os.Getenv("ETH_HTTP_URL") - if len(wsUrl) == 0 || len(httpUrl) == 0 { - fmt.Println("ETH_URL & ETH_HTTP_URL are required for this script.") - os.Exit(1) - } - - fs := flag.NewFlagSet("ocr2vrf-setup", flag.ExitOnError) - - keyID := fs.String("key-id", "aee00d81f822f882b6fe28489822f59ebb21ea95c0ae21d9f67c0239461148fc", "key ID") - linkAddress := fs.String("link-address", "", "LINK token address") - linkEthFeed := fs.String("link-eth-feed", "", "LINK-ETH feed address") - useForwarder := fs.Bool("use-forwarder", false, "boolean to use the forwarder") - confDelays := fs.String("conf-delays", "1,2,3,4,5,6,7,8", "8 confirmation delays") - weiPerUnitLink := fs.String("wei-per-unit-link", "6e16", "wei per unit link price for feed") - beaconPeriodBlocks := fs.Int64("beacon-period-blocks", 3, "beacon period in blocks") - subscriptionBalanceString := fs.String("subscription-balance", "1e19", "amount to fund subscription") - maxCallbackGasLimit := fs.Uint("max-cb-gas-limit", 2.5e6, "max callback gas limit") - maxCallbackArgumentsLength := fs.Uint("max-cb-args-length", 32*10 /* 10 EVM words */, "max callback arguments length") - - apiFile := fs.String("api", "../../../tools/secrets/apicredentials", "api credentials file") - passwordFile := fs.String("password", "../../../tools/secrets/password.txt", "password file") - databasePrefix := fs.String("database-prefix", "postgres://postgres:postgres_password_padded_for_security@localhost:5432/ocr2vrf-test", "database prefix") - databaseSuffixes := fs.String("database-suffixes", "sslmode=disable", "database parameters to be added") - nodeCount := fs.Int("node-count", 6, "number of nodes") - fundingAmount := fs.Int64("funding-amount", 1e17, "amount to fund nodes") // .1 ETH - resetDatabase := fs.Bool("reset-database", true, "boolean to reset database") - - helpers.ParseArgs(fs, os.Args[2:]) - - if *nodeCount < 6 { - fmt.Println("Node count too low for OCR2VRF job, need at least 6.") - os.Exit(1) - } - - delays := helpers.ParseIntSlice(*confDelays) - if len(delays) != 8 { - fmt.Println("confDelays must have a length of 8") - os.Exit(1) - } - - var link common.Address - if *linkAddress == "" { - link = helpers.DeployLinkToken(e) - } else { - link = common.HexToAddress(*linkAddress) - } - - // Deploy DKG and VRF contracts, and add VRF - // as a consumer of DKG events. - fmt.Println("Deploying DKG contract...") - dkgAddress := deployDKG(e) - - // Deploy a new feed if needed - var feedAddress common.Address - if *linkEthFeed == "" { - fmt.Println("Deploying LINK-ETH feed...") - feedAddress = helpers.DeployLinkEthFeed(e, *linkAddress, decimal.RequireFromString(*weiPerUnitLink).BigInt()) - } else { - feedAddress = common.HexToAddress(*linkEthFeed) - } - - fmt.Println("Deploying VRF coordinator...") - vrfCoordinatorAddress, vrfCoordinator := deployVRFCoordinator(e, big.NewInt(*beaconPeriodBlocks), link.String(), feedAddress.String()) - - fmt.Println("Configuring VRF coordinator...") - configureVRFCoordinator(e, vrfCoordinator, uint32(*maxCallbackGasLimit), uint32(*maxCallbackArgumentsLength)) - - fmt.Println("Deploying VRF beacon...") - vrfBeaconAddress := deployVRFBeacon(e, vrfCoordinatorAddress.String(), link.String(), dkgAddress.String(), *keyID) - - fmt.Println("Adding VRF Beacon as DKG client...") - addClientToDKG(e, dkgAddress.String(), *keyID, vrfBeaconAddress.String()) - - fmt.Println("Adding VRF Beacon as producer in VRF Coordinator") - setProducer(e, vrfCoordinatorAddress.String(), vrfBeaconAddress.String()) - - fmt.Println("Deploying beacon consumer...") - consumerAddress := deployVRFBeaconCoordinatorConsumer(e, vrfCoordinatorAddress.String(), false, big.NewInt(*beaconPeriodBlocks)) - - fmt.Println("Creating subscription...") - createSubscription(e, vrfCoordinatorAddress.String()) - subID := findSubscriptionID(e, vrfCoordinatorAddress.String()) - - fmt.Println("Adding consumer to subscription...") - addConsumer(e, vrfCoordinatorAddress.String(), consumerAddress.String(), subID) - - subscriptionBalance := decimal.RequireFromString(*subscriptionBalanceString).BigInt() - if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { - fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, vrfCoordinatorAddress.String(), link.String(), subscriptionBalance, subID) - } else { - fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") - } - - var forwarderAddresses []common.Address - var forwarderAddressesStrings []string - // If using the forwarder, set up a forwarder for each node. - if *useForwarder { - fmt.Println("Deploying transaction forwarders...") - for i := 0; i < *nodeCount-1; i++ { - // Deploy an authorized forwarder, and add it to the list of forwarders. - f := deployAuthorizedForwarder(e, link, e.Owner.From) - forwarderAddresses = append(forwarderAddresses, f) - forwarderAddressesStrings = append(forwarderAddressesStrings, f.String()) - } - fmt.Printf("ForwarderAddresses : %v", forwarderAddressesStrings) - } - - fmt.Println("Deploying batch beacon consumer...") - loadTestConsumerAddress := deployLoadTestVRFBeaconCoordinatorConsumer(e, vrfCoordinatorAddress.String(), false, big.NewInt(*beaconPeriodBlocks)) - addConsumer(e, vrfCoordinatorAddress.String(), loadTestConsumerAddress.String(), subID) - - fmt.Println("Configuring nodes with OCR2VRF jobs...") - var ( - onChainPublicKeys []string - offChainPublicKeys []string - configPublicKeys []string - peerIDs []string - transmitters []string - dkgEncrypters []string - dkgSigners []string - sendingKeys [][]string - ) - - for i := 0; i < *nodeCount; i++ { - flagSet := flag.NewFlagSet("run-ocr2vrf-job-creation", flag.ExitOnError) - flagSet.String("api", *apiFile, "api file") - flagSet.String("password", *passwordFile, "password file") - flagSet.String("vrfpassword", *passwordFile, "vrf password file") - flagSet.String("bootstrapPort", fmt.Sprintf("%d", 8000), "port of bootstrap") - flagSet.Int64("chainID", e.ChainID, "the chain ID") - flagSet.Bool("applyInitServerConfig", true, "override for using initServerConfig in App.Before") - - flagSet.String("job-type", string(jobTypeOCR2VRF), "the job type") - - // used by bootstrap template instantiation - flagSet.String("contractID", dkgAddress.String(), "the contract to get peers from") - - // DKG args - flagSet.String("keyID", *keyID, "") - flagSet.String("dkg-address", dkgAddress.String(), "the contract address of the DKG") - - // VRF args - flagSet.String("vrf-beacon-address", vrfBeaconAddress.String(), "the contract address of the VRF Beacon") - flagSet.String("vrf-coordinator-address", vrfCoordinatorAddress.String(), "the contract address of the VRF Coordinator") - flagSet.String("link-eth-feed-address", feedAddress.Hex(), "link eth feed address") - - // Apply forwarder args if using the forwarder. - if i > 0 && *useForwarder { - flagSet.Bool("use-forwarder", *useForwarder, "use a transaction forwarder") - flagSet.String("forwarder-address", forwarderAddressesStrings[i-1], "transaction forwarder address") - } - - flagSet.Bool("dangerWillRobinson", *resetDatabase, "for resetting databases") - flagSet.Bool("isBootstrapper", i == 0, "is first node") - bootstrapperPeerID := "" - if len(peerIDs) != 0 { - bootstrapperPeerID = peerIDs[0] - } - flagSet.String("bootstrapperPeerID", bootstrapperPeerID, "peerID of first node") - - payload := SetupNode(e, flagSet, i, *databasePrefix, *databaseSuffixes, *useForwarder, *resetDatabase, wsUrl, httpUrl) - - onChainPublicKeys = append(onChainPublicKeys, payload.OnChainPublicKey) - offChainPublicKeys = append(offChainPublicKeys, payload.OffChainPublicKey) - configPublicKeys = append(configPublicKeys, payload.ConfigPublicKey) - peerIDs = append(peerIDs, payload.PeerID) - transmitters = append(transmitters, payload.Transmitter) - dkgEncrypters = append(dkgEncrypters, payload.DkgEncrypt) - dkgSigners = append(dkgSigners, payload.DkgSign) - sendingKeys = append(sendingKeys, payload.SendingKeys) - } - - var nodesToFund []string - - // If using the forwarder, set up a forwarder for each node. - if *useForwarder { - fmt.Println("Setting authorized senders...") - for i, f := range forwarderAddresses { - // Convert the sending strings for a transmitter to addresses. - var sendinKeysAddresses []common.Address - sendingKeysStrings := sendingKeys[i+1] - for _, s := range sendingKeysStrings { - sendinKeysAddresses = append(sendinKeysAddresses, common.HexToAddress(s)) - } - - // Set authorized senders for the corresponding forwarder. - setAuthorizedSenders(e, f, sendinKeysAddresses) - - // Fund the sending keys. - nodesToFund = append(nodesToFund, sendingKeysStrings...) - - // Set the authorized forwarder as the OCR transmitter. - transmitters[i+1] = f.String() - } - } else { - nodesToFund = append(nodesToFund, transmitters[1:]...) - } - - var payees []common.Address - var reportTransmitters []common.Address // all transmitters excluding bootstrap - for _, t := range transmitters[1:] { - payees = append(payees, e.Owner.From) - reportTransmitters = append(reportTransmitters, common.HexToAddress(t)) - } - - fmt.Printf("Setting EOA: %s as payee for transmitters: %v \n", e.Owner.From, reportTransmitters) - setPayees(e, vrfBeaconAddress.String(), reportTransmitters, payees) - - fmt.Println("Funding transmitters...") - helpers.FundNodes(e, nodesToFund, big.NewInt(*fundingAmount)) - - printStandardCommands( - dkgAddress, - vrfBeaconAddress, - consumerAddress, - loadTestConsumerAddress, - keyID, - confDelays, - onChainPublicKeys[1:], - offChainPublicKeys[1:], - configPublicKeys[1:], - peerIDs[1:], - transmitters[1:], - dkgEncrypters[1:], - dkgSigners[1:], - subID.String(), - ) -} - -func setupOCR2VRFNodesForInfraWithForwarder(e helpers.Environment) { - fs := flag.NewFlagSet("ocr2vrf-setup-infra", flag.ExitOnError) - - keyID := fs.String("key-id", "aee00d81f822f882b6fe28489822f59ebb21ea95c0ae21d9f67c0239461148fc", "key ID") - linkAddress := fs.String("link-address", "", "LINK token address") - linkEthFeed := fs.String("link-eth-feed", "", "LINK-ETH feed address") - confDelays := fs.String("conf-delays", "1,2,3,4,5,6,7,8", "8 confirmation delays") - beaconPeriodBlocks := fs.Int64("beacon-period-blocks", 3, "beacon period in blocks") - subscriptionBalanceString := fs.String("subscription-balance", "1e19", "amount to fund subscription") - - peerIDsString := fs.String("peer-ids", "", "peer ids") - dkgSignersString := fs.String("dkg-sign-keys", "", "dkg signing keys") - dkgEncryptersString := fs.String("dkg-encrypt-keys", "", "dkg encrypt keys") - ocr2KeyBundleIDsString := fs.String("key-bundle-ids", "", "ocr2 key bundle ids") - onChainPublicKeysString := fs.String("on-chain-public-keys", "", "ocr2 on-chain public keys") - offChainPublicKeysString := fs.String("off-chain-public-keys", "", "ocr2 off-chain public keys") - configPublicKeysString := fs.String("config-public-keys", "", "ocr2 config public keys") - ethSendingKeysString := fs.String("eth-sending-keys", "", "eth sending keys") - - nodeCount := fs.Int("node-count", 6, "number of nodes") - fundingAmount := fs.Int64("funding-amount", 1e17, "amount to fund nodes") // .1 ETH - - helpers.ParseArgs( - fs, - os.Args[2:], - "link-address", - "link-eth-feed", - "dkg-sign-keys", - "dkg-encrypt-keys", - "key-bundle-ids", - "on-chain-public-keys", - "off-chain-public-keys", - "config-public-keys", - "eth-sending-keys", - "peer-ids", - ) - - peerIDs := strings.Split(*peerIDsString, ",") - dkgSigners := strings.Split(*dkgSignersString, ",") - dkgEncrypters := strings.Split(*dkgEncryptersString, ",") - ocr2KeyBundleIDs := strings.Split(*ocr2KeyBundleIDsString, ",") - onChainPublicKeys := strings.Split(*onChainPublicKeysString, ",") - offChainPublicKeys := strings.Split(*offChainPublicKeysString, ",") - configPublicKeys := strings.Split(*configPublicKeysString, ",") - - var sendingKeys [][]string - flatSendingKeys := strings.Split(*ethSendingKeysString, ",") - sendingKeysPerNode := len(flatSendingKeys) / (*nodeCount - 1) - for i := 0; i < *nodeCount-1; i++ { - sendingKeys = append(sendingKeys, flatSendingKeys[i*sendingKeysPerNode:i*sendingKeysPerNode+sendingKeysPerNode]) - } - - if *nodeCount < 6 { - fmt.Println("Node count too low for OCR2VRF job, need at least 6.") - os.Exit(1) - } - - delays := helpers.ParseIntSlice(*confDelays) - if len(delays) != 8 { - fmt.Println("confDelays must have a length of 8") - os.Exit(1) - } - - link := common.HexToAddress(*linkAddress) - feedAddress := common.HexToAddress(*linkEthFeed) - - // Deploy DKG and VRF contracts, and add VRF - // as a consumer of DKG events. - fmt.Println("Deploying DKG contract...") - dkgAddress := deployDKG(e) - - fmt.Println("Deploying VRF coordinator...") - vrfCoordinatorAddress, _ := deployVRFCoordinator(e, big.NewInt(*beaconPeriodBlocks), link.String(), feedAddress.String()) - - fmt.Println("Deploying VRF beacon...") - vrfBeaconAddress := deployVRFBeacon(e, vrfCoordinatorAddress.String(), link.String(), dkgAddress.String(), *keyID) - - fmt.Println("Adding VRF Beacon as DKG client...") - addClientToDKG(e, dkgAddress.String(), *keyID, vrfBeaconAddress.String()) - - fmt.Println("Adding VRF Beacon as producer in VRF Coordinator") - setProducer(e, vrfCoordinatorAddress.String(), vrfBeaconAddress.String()) - - fmt.Println("Deploying beacon consumer...") - consumerAddress := deployVRFBeaconCoordinatorConsumer(e, vrfCoordinatorAddress.String(), false, big.NewInt(*beaconPeriodBlocks)) - - fmt.Println("Creating subscription...") - createSubscription(e, vrfCoordinatorAddress.String()) - - subID := findSubscriptionID(e, vrfCoordinatorAddress.String()) - - fmt.Println("Adding consumer to subscription...") - addConsumer(e, vrfCoordinatorAddress.String(), consumerAddress.String(), subID) - - subscriptionBalance := decimal.RequireFromString(*subscriptionBalanceString).BigInt() - if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { - fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, vrfCoordinatorAddress.String(), link.String(), subscriptionBalance, subID) - } else { - fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") - } - - var forwarderAddresses []common.Address - var forwarderAddressesStrings []string - var nodesToFund []string - var transmitters []string - - // Set up a forwarder for each node. - fmt.Println("Deploying transaction forwarders...") - for i := 0; i < *nodeCount-1; i++ { - // Deploy an authorized forwarder, and add it to the list of forwarders. - f := deployAuthorizedForwarder(e, link, e.Owner.From) - forwarderAddresses = append(forwarderAddresses, f) - forwarderAddressesStrings = append(forwarderAddressesStrings, f.String()) - } - - // Assign the sending keys to the deployed forwarders. - fmt.Printf("ForwarderAddresses : %v\n", forwarderAddressesStrings) - for i, f := range forwarderAddresses { - // Convert the sending strings for a transmitter to addresses. - var sendinKeysAddresses []common.Address - sendingKeysStrings := sendingKeys[i] - for _, s := range sendingKeysStrings { - sendinKeysAddresses = append(sendinKeysAddresses, common.HexToAddress(s)) - } - - // Set authorized senders for the corresponding forwarder. - setAuthorizedSenders(e, f, sendinKeysAddresses) - - // Fund the sending keys. - nodesToFund = append(nodesToFund, sendingKeysStrings...) - - // Set the authorized forwarder as the OCR transmitter. - transmitters = append(transmitters, f.String()) - } - - var payees []common.Address - var reportTransmitters []common.Address - for _, t := range transmitters { - payees = append(payees, e.Owner.From) - reportTransmitters = append(reportTransmitters, common.HexToAddress(t)) - } - - fmt.Printf("Setting EOA: %s as payee for transmitters: %v \n", e.Owner.From, reportTransmitters) - setPayees(e, vrfBeaconAddress.String(), reportTransmitters, payees) - - fmt.Println("Funding transmitters...") - helpers.FundNodes(e, nodesToFund, big.NewInt(*fundingAmount)) - - fmt.Println("Deploying batch beacon consumer...") - loadTestConsumerAddress := deployLoadTestVRFBeaconCoordinatorConsumer(e, vrfCoordinatorAddress.String(), false, big.NewInt(*beaconPeriodBlocks)) - addConsumer(e, vrfCoordinatorAddress.String(), loadTestConsumerAddress.String(), subID) - - for i := 0; i < *nodeCount; i++ { - // Apply forwarder args if using the forwarder. - if i > 0 { - adjustedIndex := i - 1 - vrfJob := fmt.Sprintf( - cmd.OCR2VRFTemplate, - e.ChainID, - vrfBeaconAddress.String(), - ocr2KeyBundleIDs[adjustedIndex], - forwarderAddresses[adjustedIndex].String(), - true, // forwardingAllowed - "", // P2P Bootstrapper - e.ChainID, - sendingKeys[adjustedIndex], - dkgEncrypters[adjustedIndex], - dkgSigners[adjustedIndex], - *keyID, - dkgAddress.String(), - vrfCoordinatorAddress.String(), - *linkEthFeed, - ) - fmt.Printf("VRF JOB FOR NODE %d:\n%v\n", i-1, vrfJob) // zero-based index to match infra. - } else { - bootstrapJob := fmt.Sprintf(cmd.BootstrapTemplate, e.ChainID, dkgAddress.String(), e.ChainID) - fmt.Printf("VRF BOOTSTRAP JOB:\n%v\n", bootstrapJob) - } - } - printStandardCommands( - dkgAddress, - vrfBeaconAddress, - consumerAddress, - loadTestConsumerAddress, - keyID, - confDelays, - onChainPublicKeys, - offChainPublicKeys, - configPublicKeys, - peerIDs, - transmitters, - dkgEncrypters, - dkgSigners, - subID.String(), - ) -} - -func printStandardCommands( - dkgAddress common.Address, - vrfBeaconAddress common.Address, - consumerAddress common.Address, - loadTestConsumerAddress common.Address, - keyID *string, - confDelays *string, - onChainPublicKeys []string, - offChainPublicKeys []string, - configPublicKeys []string, - peerIDs []string, - transmitters []string, - dkgEncrypters []string, - dkgSigners []string, - subID string, -) { - fmt.Println("Generated dkg setConfig command:") - dkgCommand := fmt.Sprintf( - "go run . dkg-set-config -dkg-address %s -key-id %s -onchain-pub-keys %s -offchain-pub-keys %s -config-pub-keys %s -peer-ids %s -transmitters %s -dkg-encryption-pub-keys %s -dkg-signing-pub-keys %s -schedule 1,1,1,1,1", - dkgAddress.String(), - *keyID, - strings.Join(onChainPublicKeys, ","), - strings.Join(offChainPublicKeys, ","), - strings.Join(configPublicKeys, ","), - strings.Join(peerIDs, ","), - strings.Join(transmitters, ","), - strings.Join(dkgEncrypters, ","), - strings.Join(dkgSigners, ","), - ) - fmt.Println(dkgCommand) - - fmt.Println() - fmt.Println("Generated vrf setConfig command:") - vrfCommand := fmt.Sprintf( - "go run . beacon-set-config -beacon-address %s -conf-delays %s -onchain-pub-keys %s -offchain-pub-keys %s -config-pub-keys %s -peer-ids %s -transmitters %s -schedule 1,1,1,1,1", - vrfBeaconAddress.String(), - *confDelays, - strings.Join(onChainPublicKeys, ","), - strings.Join(offChainPublicKeys, ","), - strings.Join(configPublicKeys, ","), - strings.Join(peerIDs, ","), - strings.Join(transmitters, ","), - ) - fmt.Println(vrfCommand) - - fmt.Println() - fmt.Println("Consumer address:", consumerAddress.String()) - fmt.Println("Consumer request command:") - requestCommand := fmt.Sprintf( - "go run . consumer-request-randomness -consumer-address %s -sub-id %s", - consumerAddress.Hex(), subID) - fmt.Println(requestCommand) - fmt.Println() - - fmt.Println("Consumer callback request command:") - callbackCommand := fmt.Sprintf( - "go run . consumer-request-callback -consumer-address %s -sub-id %s", - consumerAddress.Hex(), subID) - fmt.Println(callbackCommand) - fmt.Println() - - fmt.Println("Consumer callback batch request command:") - callbackCommand = fmt.Sprintf( - "go run . consumer-request-callback-batch -consumer-address %s -sub-id %s -batch-size ", - loadTestConsumerAddress.Hex(), subID) - fmt.Println(callbackCommand) - fmt.Println() - - fmt.Println("Consumer redeem randomness command:") - redeemCommand := fmt.Sprintf( - "go run . consumer-redeem-randomness -consumer-address %s -sub-id %s -request-id ", - consumerAddress.Hex(), subID) - fmt.Println(redeemCommand) - fmt.Println() -} - -func SetupNode( - e helpers.Environment, - flagSet *flag.FlagSet, - nodeIdx int, - databasePrefix, - databaseSuffixes string, - useForwarder bool, - resetDB bool, - wsUrl string, - httpUrl string, -) *cmd.SetupOCR2VRFNodePayload { - configureEnvironmentVariables((useForwarder) && (nodeIdx > 0), e.ChainID, wsUrl, httpUrl, nodeIdx, databasePrefix, databaseSuffixes) - - client := newSetupClient() - app := cmd.NewApp(client) - ctx := cli.NewContext(app, flagSet, nil) - - defer func() { - err := app.After(ctx) - helpers.PanicErr(err) - }() - - err := app.Before(ctx) - helpers.PanicErr(err) - - if resetDB { - resetDatabase(client, ctx) - } - - return setupOCR2VRFNodeFromClient(client, ctx, e) -} diff --git a/core/scripts/ocr2vrf/util.go b/core/scripts/ocr2vrf/util.go deleted file mode 100644 index d19e7289ab4..00000000000 --- a/core/scripts/ocr2vrf/util.go +++ /dev/null @@ -1,619 +0,0 @@ -package main - -import ( - "context" - "crypto/ed25519" - "encoding/hex" - "fmt" - "math/big" - "os" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/urfave/cli" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/edwards25519" - "go.dedis.ch/kyber/v3/pairing" - - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - "github.com/smartcontractkit/chainlink/v2/core/cmd" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" - dkgContract "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/load_test_beacon_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" -) - -var ( - suite pairing.Suite = &altbn_128.PairingSuite{} - g1 = suite.G1() - g2 = suite.G2() - tomlConfigTemplate = ` - [P2P.V2] - ListenAddresses = ["127.0.0.1:8000"] - - [Feature] - LogPoller = true - - [OCR2] - Enabled = true - - [[EVM]] - FinalityDepth = 10 - ChainID = '%d' - - [EVM.Transactions] - ForwardersEnabled = %t - - [EVM.HeadTracker] - HistoryDepth = 1 - - [[EVM.Nodes]] - Name = "chain1" - HTTPURL = "%s" - WSURL = "%s" - ` -) - -func deployDKG(e helpers.Environment) common.Address { - _, tx, _, err := dkgContract.DeployDKG(e.Owner, e.Ec) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) -} - -func deployVRFCoordinator(e helpers.Environment, beaconPeriodBlocks *big.Int, linkAddress, linkEthFeed string) (common.Address, *vrf_coordinator.VRFCoordinator) { - _, tx, coordinator, err := vrf_coordinator.DeployVRFCoordinator( - e.Owner, - e.Ec, - beaconPeriodBlocks, - common.HexToAddress(linkAddress), - ) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID), coordinator -} - -func configureVRFCoordinator(e helpers.Environment, coordinator *vrf_coordinator.VRFCoordinator, maxCbGasLimit, maxCbArgsLen uint32) *gethtypes.Receipt { - tx, err := coordinator.SetCallbackConfig(e.Owner, vrf_coordinator.VRFCoordinatorCallbackConfig{ - MaxCallbackGasLimit: maxCbGasLimit, - MaxCallbackArgumentsLength: maxCbArgsLen, - }) - helpers.PanicErr(err) - return helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "vrf coordinator setConfig") -} - -func deployAuthorizedForwarder(e helpers.Environment, link common.Address, owner common.Address) common.Address { - _, tx, _, err := authorized_forwarder.DeployAuthorizedForwarder(e.Owner, e.Ec, link, owner, common.Address{}, []byte{}) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) -} - -func setAuthorizedSenders(e helpers.Environment, forwarder common.Address, senders []common.Address) { - f, err := authorized_forwarder.NewAuthorizedForwarder(forwarder, e.Ec) - helpers.PanicErr(err) - tx, err := f.SetAuthorizedSenders(e.Owner, senders) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func deployVRFBeacon(e helpers.Environment, coordinatorAddress, linkAddress, dkgAddress, keyID string) common.Address { - keyIDBytes := decodeHexTo32ByteArray(keyID) - _, tx, _, err := vrf_beacon.DeployVRFBeacon(e.Owner, e.Ec, common.HexToAddress(linkAddress), common.HexToAddress(coordinatorAddress), common.HexToAddress(dkgAddress), keyIDBytes) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) -} - -func deployVRFBeaconCoordinatorConsumer(e helpers.Environment, coordinatorAddress string, shouldFail bool, beaconPeriodBlocks *big.Int) common.Address { - _, tx, _, err := vrf_beacon_consumer.DeployBeaconVRFConsumer(e.Owner, e.Ec, common.HexToAddress(coordinatorAddress), shouldFail, beaconPeriodBlocks) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) -} - -func deployLoadTestVRFBeaconCoordinatorConsumer(e helpers.Environment, coordinatorAddress string, shouldFail bool, beaconPeriodBlocks *big.Int) common.Address { - _, tx, _, err := load_test_beacon_consumer.DeployLoadTestBeaconVRFConsumer(e.Owner, e.Ec, common.HexToAddress(coordinatorAddress), shouldFail, beaconPeriodBlocks) - helpers.PanicErr(err) - return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) -} - -func addClientToDKG(e helpers.Environment, dkgAddress string, keyID string, clientAddress string) { - keyIDBytes := decodeHexTo32ByteArray(keyID) - - dkg, err := dkgContract.NewDKG(common.HexToAddress(dkgAddress), e.Ec) - helpers.PanicErr(err) - - tx, err := dkg.AddClient(e.Owner, keyIDBytes, common.HexToAddress(clientAddress)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func removeClientFromDKG(e helpers.Environment, dkgAddress string, keyID string, clientAddress string) { - keyIDBytes := decodeHexTo32ByteArray(keyID) - - dkg, err := dkgContract.NewDKG(common.HexToAddress(dkgAddress), e.Ec) - helpers.PanicErr(err) - - tx, err := dkg.RemoveClient(e.Owner, keyIDBytes, common.HexToAddress(clientAddress)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func setDKGConfig(e helpers.Environment, dkgAddress string, c dkgSetConfigArgs) { - oracleIdentities := toOraclesIdentityList( - helpers.ParseAddressSlice(c.onchainPubKeys), - strings.Split(c.offchainPubKeys, ","), - strings.Split(c.configPubKeys, ","), - strings.Split(c.peerIDs, ","), - strings.Split(c.transmitters, ",")) - - ed25519Suite := edwards25519.NewBlakeSHA256Ed25519() - var signingKeys []kyber.Point - for _, signingKey := range strings.Split(c.dkgSigningPubKeys, ",") { - signingKeyBytes, err := hex.DecodeString(signingKey) - helpers.PanicErr(err) - signingKeyPoint := ed25519Suite.Point() - helpers.PanicErr(signingKeyPoint.UnmarshalBinary(signingKeyBytes)) - signingKeys = append(signingKeys, signingKeyPoint) - } - - altbn128Suite := &altbn_128.PairingSuite{} - var encryptionKeys []kyber.Point - for _, encryptionKey := range strings.Split(c.dkgEncryptionPubKeys, ",") { - encryptionKeyBytes, err := hex.DecodeString(encryptionKey) - helpers.PanicErr(err) - encryptionKeyPoint := altbn128Suite.G1().Point() - helpers.PanicErr(encryptionKeyPoint.UnmarshalBinary(encryptionKeyBytes)) - encryptionKeys = append(encryptionKeys, encryptionKeyPoint) - } - - keyIDBytes := decodeHexTo32ByteArray(c.keyID) - - offchainConfig, err := dkg.OffchainConfig(encryptionKeys, signingKeys, &altbn_128.G1{}, &ocr2vrftypes.PairingTranslation{ - Suite: &altbn_128.PairingSuite{}, - }) - helpers.PanicErr(err) - onchainConfig, err := dkg.OnchainConfig(dkg.KeyID(keyIDBytes)) - helpers.PanicErr(err) - - fmt.Println("dkg offchain config:", hex.EncodeToString(offchainConfig)) - fmt.Println("dkg onchain config:", hex.EncodeToString(onchainConfig)) - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( - c.deltaProgress, - c.deltaResend, - c.deltaRound, - c.deltaGrace, - c.deltaStage, - c.maxRounds, - helpers.ParseIntSlice(c.schedule), - oracleIdentities, - offchainConfig, - c.maxDurationQuery, - c.maxDurationObservation, - c.maxDurationReport, - c.maxDurationAccept, - c.maxDurationTransmit, - int(c.f), - onchainConfig) - - helpers.PanicErr(err) - - dkg := newDKG(common.HexToAddress(dkgAddress), e.Ec) - - tx, err := dkg.SetConfig(e.Owner, helpers.ParseAddressSlice(c.onchainPubKeys), helpers.ParseAddressSlice(c.transmitters), f, onchainConfig, offchainConfigVersion, offchainConfig) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func (c *vrfBeaconSetConfigArgs) setVRFBeaconConfig(e helpers.Environment, vrfBeaconAddr string) { - oracleIdentities := toOraclesIdentityList( - helpers.ParseAddressSlice(c.onchainPubKeys), - strings.Split(c.offchainPubKeys, ","), - strings.Split(c.configPubKeys, ","), - strings.Split(c.peerIDs, ","), - strings.Split(c.transmitters, ",")) - - confDelays := make(map[uint32]struct{}) - for _, c := range strings.Split(c.confDelays, ",") { - confDelay, err := strconv.ParseUint(c, 0, 32) - helpers.PanicErr(err) - confDelays[uint32(confDelay)] = struct{}{} - } - - onchainConfig := ocr2vrf.OnchainConfig(confDelays) - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( - c.deltaProgress, - c.deltaResend, - c.deltaRound, - c.deltaGrace, - c.deltaStage, - c.maxRounds, - helpers.ParseIntSlice(c.schedule), - oracleIdentities, - ocr2vrf.OffchainConfig(&c.coordinatorConfig), // off-chain config - c.maxDurationQuery, - c.maxDurationObservation, - c.maxDurationReport, - c.maxDurationAccept, - c.maxDurationTransmit, - int(c.f), - onchainConfig) - - helpers.PanicErr(err) - - beacon := newVRFBeacon(common.HexToAddress(vrfBeaconAddr), e.Ec) - - tx, err := beacon.SetConfig(e.Owner, helpers.ParseAddressSlice(c.onchainPubKeys), helpers.ParseAddressSlice(c.transmitters), f, onchainConfig, offchainConfigVersion, offchainConfig) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func setProducer(e helpers.Environment, vrfCoordinatorAddr, vrfBeaconAddr string) { - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - - tx, err := coordinator.SetProducer(e.Owner, common.HexToAddress(vrfBeaconAddr)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func createSubscription(e helpers.Environment, vrfCoordinatorAddr string) { - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - - tx, err := coordinator.CreateSubscription(e.Owner) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func getSubscription(e helpers.Environment, vrfCoordinatorAddr string, subId *big.Int) vrf_coordinator.GetSubscription { - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - - sub, err := coordinator.GetSubscription(nil, subId) - helpers.PanicErr(err) - return sub -} - -// returns subscription ID that belongs to the given owner. Returns result found first -func findSubscriptionID(e helpers.Environment, vrfCoordinatorAddr string) *big.Int { - // Use most recent 500 blocks as search window. - head, err := e.Ec.BlockNumber(context.Background()) - helpers.PanicErr(err) - fopts := &bind.FilterOpts{ - Start: head - 500, - } - - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - subscriptionIterator, err := coordinator.FilterSubscriptionCreated(fopts, nil, []common.Address{e.Owner.From}) - helpers.PanicErr(err) - - if !subscriptionIterator.Next() { - helpers.PanicErr(fmt.Errorf("expected at leats 1 subID for the given owner %s", e.Owner.From.Hex())) - } - return subscriptionIterator.Event.SubId -} - -func addConsumer(e helpers.Environment, vrfCoordinatorAddr, consumerAddr string, subId *big.Int) { - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - - tx, err := coordinator.AddConsumer(e.Owner, subId, common.HexToAddress(consumerAddr)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func setPayees(e helpers.Environment, vrfBeaconAddr string, transmitters, payees []common.Address) { - beacon := newVRFBeacon(common.HexToAddress(vrfBeaconAddr), e.Ec) - - tx, err := beacon.SetPayees(e.Owner, transmitters, payees) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func eoaFundSubscription(e helpers.Environment, coordinatorAddress, linkAddress string, amount, subID *big.Int) { - linkToken, err := link_token_interface.NewLinkToken(common.HexToAddress(linkAddress), e.Ec) - helpers.PanicErr(err) - bal, err := linkToken.BalanceOf(nil, e.Owner.From) - helpers.PanicErr(err) - fmt.Println("Initial account balance:", bal, e.Owner.From.String(), "Funding amount:", amount.String()) - b, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) - helpers.PanicErr(err) - tx, err := linkToken.TransferAndCall(e.Owner, common.HexToAddress(coordinatorAddress), amount, b) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("sub ID: %d", subID)) -} - -func toOraclesIdentityList(onchainPubKeys []common.Address, offchainPubKeys, configPubKeys, peerIDs, transmitters []string) []confighelper.OracleIdentityExtra { - offchainPubKeysBytes := []types.OffchainPublicKey{} - for _, pkHex := range offchainPubKeys { - pkBytes, err := hex.DecodeString(pkHex) - helpers.PanicErr(err) - pkBytesFixed := [ed25519.PublicKeySize]byte{} - n := copy(pkBytesFixed[:], pkBytes) - if n != ed25519.PublicKeySize { - panic("wrong num elements copied") - } - - offchainPubKeysBytes = append(offchainPubKeysBytes, types.OffchainPublicKey(pkBytesFixed)) - } - - configPubKeysBytes := []types.ConfigEncryptionPublicKey{} - for _, pkHex := range configPubKeys { - pkBytes, err := hex.DecodeString(pkHex) - helpers.PanicErr(err) - - pkBytesFixed := [ed25519.PublicKeySize]byte{} - n := copy(pkBytesFixed[:], pkBytes) - if n != ed25519.PublicKeySize { - panic("wrong num elements copied") - } - - configPubKeysBytes = append(configPubKeysBytes, types.ConfigEncryptionPublicKey(pkBytesFixed)) - } - - o := []confighelper.OracleIdentityExtra{} - for index := range configPubKeys { - o = append(o, confighelper.OracleIdentityExtra{ - OracleIdentity: confighelper.OracleIdentity{ - OnchainPublicKey: onchainPubKeys[index][:], - OffchainPublicKey: offchainPubKeysBytes[index], - PeerID: peerIDs[index], - TransmitAccount: types.Account(transmitters[index]), - }, - ConfigEncryptionPublicKey: configPubKeysBytes[index], - }) - } - return o -} - -func requestRandomness(e helpers.Environment, coordinatorAddress string, numWords uint16, subID, confDelay *big.Int) { - coordinator := newVRFCoordinator(common.HexToAddress(coordinatorAddress), e.Ec) - - tx, err := coordinator.RequestRandomness(e.Owner, confDelay, numWords, confDelay, nil) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func redeemRandomness(e helpers.Environment, coordinatorAddress string, requestID, subID *big.Int) { - coordinator := newVRFCoordinator(common.HexToAddress(coordinatorAddress), e.Ec) - - tx, err := coordinator.RedeemRandomness(e.Owner, subID, requestID, nil) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func requestRandomnessFromConsumer(e helpers.Environment, consumerAddress string, numWords uint16, subID, confDelay *big.Int) *big.Int { - consumer := newVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - - tx, err := consumer.TestRequestRandomness(e.Owner, numWords, subID, confDelay) - helpers.PanicErr(err) - receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) - - periodBlocks, err := consumer.IBeaconPeriodBlocks(nil) - helpers.PanicErr(err) - - blockNumber := receipt.BlockNumber - periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) - nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - - fmt.Println("nextBeaconOutputHeight: ", nextBeaconOutputHeight) - - requestID, err := consumer.SRequestsIDs(nil, nextBeaconOutputHeight, confDelay) - helpers.PanicErr(err) - fmt.Println("requestID: ", requestID) - - return requestID -} - -func readRandomness( - e helpers.Environment, - consumerAddress string, - requestID *big.Int, - numWords int) { - consumer := newVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - for i := 0; i < numWords; i++ { - r, err := consumer.SReceivedRandomnessByRequestID(nil, requestID, big.NewInt(int64(i))) - helpers.PanicErr(err) - fmt.Println("random word", i, ":", r.String()) - } -} - -func requestRandomnessCallback( - e helpers.Environment, - consumerAddress string, - numWords uint16, - subID, confDelay *big.Int, - callbackGasLimit uint32, - args []byte, -) (requestID *big.Int) { - consumer := newVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - - tx, err := consumer.TestRequestRandomnessFulfillment(e.Owner, subID, numWords, confDelay, callbackGasLimit, args) - helpers.PanicErr(err) - receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "TestRequestRandomnessFulfillment") - - periodBlocks, err := consumer.IBeaconPeriodBlocks(nil) - helpers.PanicErr(err) - - blockNumber := receipt.BlockNumber - periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) - nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - - fmt.Println("nextBeaconOutputHeight: ", nextBeaconOutputHeight) - - requestID, err = consumer.SRequestsIDs(nil, nextBeaconOutputHeight, confDelay) - helpers.PanicErr(err) - fmt.Println("requestID: ", requestID) - - return requestID -} - -func redeemRandomnessFromConsumer(e helpers.Environment, consumerAddress string, subID, requestID *big.Int, numWords int64) { - consumer := newVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - - tx, err := consumer.TestRedeemRandomness(e.Owner, subID, requestID) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) - - printRandomnessFromConsumer(consumer, requestID, numWords) -} - -func printRandomnessFromConsumer(consumer *vrf_beacon_consumer.BeaconVRFConsumer, requestID *big.Int, numWords int64) { - for i := int64(0); i < numWords; i++ { - randomness, err := consumer.SReceivedRandomnessByRequestID(nil, requestID, big.NewInt(0)) - helpers.PanicErr(err) - fmt.Println("random words index", i, ":", randomness.String()) - } -} - -func newVRFCoordinator(addr common.Address, client *ethclient.Client) *vrf_coordinator.VRFCoordinator { - coordinator, err := vrf_coordinator.NewVRFCoordinator(addr, client) - helpers.PanicErr(err) - return coordinator -} - -func newDKG(addr common.Address, client *ethclient.Client) *dkgContract.DKG { - dkg, err := dkgContract.NewDKG(addr, client) - helpers.PanicErr(err) - return dkg -} - -func newVRFBeaconCoordinatorConsumer(addr common.Address, client *ethclient.Client) *vrf_beacon_consumer.BeaconVRFConsumer { - consumer, err := vrf_beacon_consumer.NewBeaconVRFConsumer(addr, client) - helpers.PanicErr(err) - return consumer -} - -func newLoadTestVRFBeaconCoordinatorConsumer(addr common.Address, client *ethclient.Client) *load_test_beacon_consumer.LoadTestBeaconVRFConsumer { - consumer, err := load_test_beacon_consumer.NewLoadTestBeaconVRFConsumer(addr, client) - helpers.PanicErr(err) - return consumer -} - -func newVRFBeacon(addr common.Address, client *ethclient.Client) *vrf_beacon.VRFBeacon { - beacon, err := vrf_beacon.NewVRFBeacon(addr, client) - helpers.PanicErr(err) - return beacon -} - -func decodeHexTo32ByteArray(val string) (byteArray [32]byte) { - decoded, err := hex.DecodeString(val) - helpers.PanicErr(err) - if len(decoded) != 32 { - panic(fmt.Sprintf("expected value to be 32 bytes but received %d bytes", len(decoded))) - } - copy(byteArray[:], decoded) - return -} - -func setupOCR2VRFNodeFromClient(client *cmd.Shell, context *cli.Context, e helpers.Environment) *cmd.SetupOCR2VRFNodePayload { - payload, err := client.ConfigureOCR2VRFNode(context, e.Owner, e.Ec) - helpers.PanicErr(err) - - return payload -} - -func configureEnvironmentVariables(useForwarder bool, chainID int64, wsUrl string, ethURL string, index int, databasePrefix string, databaseSuffixes string) { - // Set permitted envars for v2. - helpers.PanicErr(os.Setenv("CL_DATABASE_URL", fmt.Sprintf("%s-%d?%s", databasePrefix, index, databaseSuffixes))) - helpers.PanicErr(os.Setenv("CL_CONFIG", fmt.Sprintf(tomlConfigTemplate, chainID, useForwarder, ethURL, wsUrl))) - - // Unset prohibited envars for v2. - helpers.PanicErr(os.Unsetenv("ETH_URL")) - helpers.PanicErr(os.Unsetenv("ETH_HTTP_URL")) - helpers.PanicErr(os.Unsetenv("ETH_CHAIN_ID")) -} - -func resetDatabase(client *cmd.Shell, context *cli.Context) { - helpers.PanicErr(client.ResetDatabase(context)) -} - -func newSetupClient() *cmd.Shell { - prompter := cmd.NewTerminalPrompter() - return &cmd.Shell{ - Renderer: cmd.RendererTable{Writer: os.Stdout}, - AppFactory: cmd.ChainlinkAppFactory{}, - KeyStoreAuthenticator: cmd.TerminalKeyStoreAuthenticator{Prompter: prompter}, - FallbackAPIInitializer: cmd.NewPromptingAPIInitializer(prompter), - Runner: cmd.ChainlinkRunner{}, - PromptingSessionRequestBuilder: cmd.NewPromptingSessionRequestBuilder(prompter), - ChangePasswordPrompter: cmd.NewChangePasswordPrompter(), - PasswordPrompter: cmd.NewPasswordPrompter(), - } -} - -func requestRandomnessCallbackBatch( - e helpers.Environment, - consumerAddress string, - numWords uint16, - subID, confDelay *big.Int, - callbackGasLimit uint32, - args []byte, - batchSize *big.Int, -) (requestID *big.Int) { - consumer := newLoadTestVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - - tx, err := consumer.TestRequestRandomnessFulfillmentBatch(e.Owner, subID, numWords, confDelay, callbackGasLimit, args, batchSize) - helpers.PanicErr(err) - receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "TestRequestRandomnessFulfillment") - - periodBlocks, err := consumer.IBeaconPeriodBlocks(nil) - helpers.PanicErr(err) - - blockNumber := receipt.BlockNumber - periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) - nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - - fmt.Println("nextBeaconOutputHeight: ", nextBeaconOutputHeight) - - requestID, err = consumer.SRequestsIDs(nil, nextBeaconOutputHeight, confDelay) - helpers.PanicErr(err) - fmt.Println("requestID: ", requestID) - - return requestID -} - -func printLoadtestResults(e helpers.Environment, consumerAddress string) { - consumer := newLoadTestVRFBeaconCoordinatorConsumer(common.HexToAddress(consumerAddress), e.Ec) - - totalRequests, err := consumer.STotalRequests(nil) - helpers.PanicErr(err) - - totalFulfilled, err := consumer.STotalFulfilled(nil) - helpers.PanicErr(err) - - avgBlocksInMil, err := consumer.SAverageFulfillmentInMillions(nil) - helpers.PanicErr(err) - - slowestBlocks, err := consumer.SSlowestFulfillment(nil) - helpers.PanicErr(err) - - fastestBlock, err := consumer.SFastestFulfillment(nil) - helpers.PanicErr(err) - - slowestRequest, err := consumer.SSlowestRequestID(nil) - helpers.PanicErr(err) - - pendingRequests, err := consumer.PendingRequests(nil) - helpers.PanicErr(err) - - fmt.Println("Total Requests: ", totalRequests.Uint64()) - fmt.Println("Total Fulfilled: ", totalFulfilled.Uint64()) - fmt.Println("Average Fulfillment Delay in Blocks: ", float64(avgBlocksInMil.Uint64())/1000000) - fmt.Println("Slowest Fulfillment Delay in Blocks: ", slowestBlocks.Uint64()) - fmt.Println("Slowest Request ID: ", slowestRequest.Uint64()) - fmt.Println("Fastest Fulfillment Delay in Blocks: ", fastestBlock.Uint64()) - fmt.Println("Pending Requests: ", pendingRequests) -} diff --git a/core/scripts/ocr2vrf/verify.go b/core/scripts/ocr2vrf/verify.go deleted file mode 100644 index 7d7fb94496a..00000000000 --- a/core/scripts/ocr2vrf/verify.go +++ /dev/null @@ -1,181 +0,0 @@ -package main - -import ( - "context" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - bn256 "github.com/ethereum/go-ethereum/crypto/bn256/google" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/mod" - "go.dedis.ch/kyber/v3/pairing" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - dkgContract "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" -) - -func getDKGLatestConfigDetails(e helpers.Environment, dkgAddress string) dkgContract.LatestConfigDetails { - dkg := newDKG(common.HexToAddress(dkgAddress), e.Ec) - dkgConfig, err := dkg.LatestConfigDetails(nil) - helpers.PanicErr(err) - - return dkgConfig -} - -func getVRFLatestConfigDetails(e helpers.Environment, beaconAddress string) vrf_beacon.LatestConfigDetails { - beacon := newVRFBeacon(common.HexToAddress(beaconAddress), e.Ec) - beaconConfig, err := beacon.LatestConfigDetails(nil) - helpers.PanicErr(err) - - return beaconConfig -} - -func getDKGKeyData(e helpers.Environment, dkgAddress string, keyID, configDigest [32]byte) dkgContract.KeyDataStructKeyData { - dkg := newDKG(common.HexToAddress(dkgAddress), e.Ec) - keyData, err := dkg.GetKey(nil, keyID, configDigest) - helpers.PanicErr(err) - - return keyData -} - -func getKeyID(e helpers.Environment, beaconAddress string) [32]byte { - beacon := newVRFBeacon(common.HexToAddress(beaconAddress), e.Ec) - keyID, err := beacon.SKeyID(nil) - helpers.PanicErr(err) - return keyID -} - -func getPublicKey(e helpers.Environment, dkgAddress string, keyID, configDigest [32]byte) kyber.Point { - keyData := getDKGKeyData(e, dkgAddress, keyID, configDigest) - kg := &altbn_128.G2{} - pk := kg.Point() - err := pk.UnmarshalBinary(keyData.PublicKey) - helpers.PanicErr(err) - return pk -} - -func getHashToCurveMessage(e helpers.Environment, height uint64, confDelay uint32, vrfConfigDigest [32]byte, pk kyber.Point) *altbn_128.HashProof { - blockNumber := big.NewInt(0).SetUint64(height) - block, err := e.Ec.BlockByNumber(context.Background(), blockNumber) - helpers.PanicErr(err) - b := ocr2vrftypes.Block{ - Height: height, - ConfirmationDelay: confDelay, - Hash: block.Hash(), - } - h := b.VRFHash(vrfConfigDigest, pk) - return altbn_128.NewHashProof(h) -} - -func getVRFSignature(e helpers.Environment, coordinatorAddress string, height, confDelay, searchWindow uint64) (proofG1X, proofG1Y *big.Int) { - // get transmission logs from requested block to requested block + search window blocks - // TODO: index transmission logs by height and confirmation delay to - // make the FilterQuery call more efficient - query := ethereum.FilterQuery{ - FromBlock: big.NewInt(0).SetUint64(height), - ToBlock: big.NewInt(0).SetUint64(height + searchWindow), - Addresses: []common.Address{ - common.HexToAddress(coordinatorAddress), - }, - Topics: [][]common.Hash{ - { - vrf_coordinator.VRFCoordinatorOutputsServed{}.Topic(), - }, - }, - } - logs, err := e.Ec.FilterLogs(context.Background(), query) - helpers.PanicErr(err) - - coordinator := newVRFCoordinator(common.HexToAddress(coordinatorAddress), e.Ec) - for _, log := range logs { - t, err := coordinator.ParseOutputsServed(log) - helpers.PanicErr(err) - for _, o := range t.OutputsServed { - if o.ConfirmationDelay.Uint64() == confDelay && o.Height == height { - proofG1X = o.ProofG1X - proofG1Y = o.ProofG1Y - } - } - } - return -} - -func verifyBeaconRandomness(e helpers.Environment, dkgAddress, beaconAddress string, coordinatorAddress string, height, confDelay, searchWindow uint64) bool { - dkgConfig := getDKGLatestConfigDetails(e, dkgAddress) - vrfConfig := getVRFLatestConfigDetails(e, beaconAddress) - keyID := getKeyID(e, beaconAddress) - pk := getPublicKey(e, dkgAddress, keyID, dkgConfig.ConfigDigest) - h := getHashToCurveMessage(e, height, uint32(confDelay), vrfConfig.ConfigDigest, pk) - hpoint := h.HashPoint - negHpoint := g1.Point() - negHpoint.Neg(hpoint) - g2Base := g2.Point().Base() - - // get BLS signature for the given height and confirmation delay - proofG1X, proofG1Y := getVRFSignature(e, coordinatorAddress, height, confDelay, searchWindow) - if proofG1X.Cmp(big.NewInt(0)) == 0 || proofG1Y.Cmp(big.NewInt(0)) == 0 { - panic("signature not found") - } - g1Proof, err := altbn_128.CoordinatesToG1(mod.NewInt(proofG1X, bn256.P), mod.NewInt(proofG1Y, bn256.P)) - helpers.PanicErr(err) - - // Perform verification of BLS signature is done using pairing function - isValid := validateSignature(suite, hpoint, pk, g1Proof) - fmt.Println("Verification Result: ", isValid) - - // Perform the same verification as above using precompiled contract 0x8 - // This should always result in same result as validateSignature() - // signature is valid iff contract0x8(-b_x, -b_y, pk_x, pk_y, p_x, p_y, g2_x, g2_y) == 1 - input := make([]byte, 384) - hb := altbn_128.LongMarshal(negHpoint) - if len(hb) != 64 { - panic("wrong length of hpoint") - } - copy(input[:64], hb[:]) - - pkb, err := pk.MarshalBinary() - helpers.PanicErr(err) - if len(pkb) != 128 { - panic("wrong length of public key") - } - copy(input[64:192], pkb) - - if len(proofG1X.Bytes()) != 32 { - panic("wrong length of VRF signature x-coordinator") - } - if len(proofG1Y.Bytes()) != 32 { - panic("wrong length of VRF signature y-coordinator") - } - copy(input[192:224], proofG1X.Bytes()) - copy(input[224:256], proofG1Y.Bytes()) - - g2b, err := g2Base.MarshalBinary() - helpers.PanicErr(err) - if len(g2b) != 128 { - panic("wrong length of altbn_128 base points") - } - copy(input[256:384], g2b) - - contract := vm.PrecompiledContractsByzantium[common.HexToAddress("0x8")] - res, err := contract.Run(input) - helpers.PanicErr(err) - isValidPrecompiledContract := big.NewInt(0).SetBytes(res).Uint64() == 1 - fmt.Println("Verification Result Using Precompiled Contract 0x8: ", isValidPrecompiledContract) - - if isValid && isValidPrecompiledContract { - return true - } - return false -} - -func validateSignature(p pairing.Suite, msg, publicKey, signature kyber.Point) bool { - return p.Pair(msg, publicKey).Equal(p.Pair(signature, p.G2().Point().Base())) -} diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 172dbafc4a4..7c3d6074c66 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ job.ServiceCtx = &service{} @@ -234,7 +233,7 @@ func (s *service) Start(context.Context) error { defer s.wg.Done() ctx, cancel := s.stopCh.NewCtx() defer cancel() - ticker := time.NewTicker(utils.WithJitter(s.pollPeriod)) + ticker := services.NewTicker(s.pollPeriod) defer ticker.Stop() for { select { diff --git a/core/services/blockhashstore/mocks/bhs.go b/core/services/blockhashstore/mocks/bhs.go index 43b4769c029..40b73aba0db 100644 --- a/core/services/blockhashstore/mocks/bhs.go +++ b/core/services/blockhashstore/mocks/bhs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/blockhashstore/mocks/timer.go b/core/services/blockhashstore/mocks/timer.go index 46212b4c021..bf593f76912 100644 --- a/core/services/blockhashstore/mocks/timer.go +++ b/core/services/blockhashstore/mocks/timer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 830c2e23377..046941aa154 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ job.ServiceCtx = &service{} @@ -241,7 +240,7 @@ func (s *service) Start(context.Context) error { defer close(s.done) ctx, cancel := s.stopCh.NewCtx() defer cancel() - ticker := time.NewTicker(utils.WithJitter(s.pollPeriod)) + ticker := services.NewTicker(s.pollPeriod) defer ticker.Stop() for { select { diff --git a/core/services/ccip/mocks/orm.go b/core/services/ccip/mocks/orm.go index ea6b07dc637..d3d7f89ba38 100644 --- a/core/services/ccip/mocks/orm.go +++ b/core/services/ccip/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 1a626bc07fc..9a2d08d000c 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -353,7 +353,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { jobORM = job.NewORM(opts.DS, pipelineORM, bridgeORM, keyStore, globalLogger) txmORM = txmgr.NewTxStore(opts.DS, globalLogger) streamRegistry = streams.NewRegistry(globalLogger, pipelineRunner) - workflowORM = workflowstore.NewDBStore(opts.DS, clockwork.NewRealClock()) + workflowORM = workflowstore.NewDBStore(opts.DS, globalLogger, clockwork.NewRealClock()) ) for _, chain := range legacyEVMChains.Slice() { @@ -500,8 +500,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger, ocr2DelegateConfig, keyStore.OCR2(), - keyStore.DKGSign(), - keyStore.DKGEncrypt(), keyStore.Eth(), opts.RelayerChainInteroperators, mailMon, diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 200d4973ed1..dc301c0967f 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -42,6 +42,32 @@ type Config struct { Solana solcfg.TOMLConfigs `toml:",omitempty"` Starknet stkcfg.TOMLConfigs `toml:",omitempty"` + + Aptos RawConfigs `toml:",omitempty"` +} + +// RawConfigs is a list of RawConfig. +type RawConfigs []RawConfig + +// RawConfig is the config used for chains that are not embedded. +type RawConfig map[string]any + +// ValidateConfig returns an error if the Config is not valid for use, as-is. +func (c *RawConfig) ValidateConfig() (err error) { + if v, ok := (*c)["Enabled"]; ok { + if _, ok := v.(*bool); !ok { + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected *bool"}) + } + } + return err +} + +func (c *RawConfig) IsEnabled() bool { + if c == nil { + return false + } + + return (*c)["Enabled"] == nil || *(*c)["Enabled"].(*bool) } // TOMLString returns a TOML encoded string. diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 5b4a6271d52..5b6b839fb5e 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -345,6 +345,15 @@ func (g *generalConfig) StarkNetEnabled() bool { return false } +func (g *generalConfig) AptosEnabled() bool { + for _, c := range g.c.Aptos { + if c.IsEnabled() { + return true + } + } + return false +} + func (g *generalConfig) WebServer() config.WebServer { return &webServerConfig{c: g.c.WebServer, s: g.secrets.WebServer, rootDir: g.RootDir} } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index b6b656c3a08..576a932e3c6 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -101,8 +101,9 @@ var ( { ChainID: ubig.NewI(1), Chain: evmcfg.Chain{ - FinalityDepth: ptr[uint32](26), - FinalityTagEnabled: ptr[bool](false), + FinalityDepth: ptr[uint32](26), + FinalityTagEnabled: ptr[bool](false), + FinalizedBlockOffset: ptr[uint32](12), }, Nodes: []*evmcfg.Node{ { @@ -504,6 +505,7 @@ func TestConfig_Marshal(t *testing.T) { FinalityDepth: ptr[uint32](42), FinalityTagEnabled: ptr[bool](false), FlagsContractAddress: mustAddress("0xae4E781a6218A8031764928E88d457937A954fC3"), + FinalizedBlockOffset: ptr[uint32](16), GasEstimator: evmcfg.GasEstimator{ Mode: ptr("SuggestedPrice"), @@ -593,6 +595,8 @@ func TestConfig_Marshal(t *testing.T) { LeaseDuration: &zeroSeconds, NodeIsSyncingEnabled: ptr(true), FinalizedBlockPollInterval: &second, + EnforceRepeatableRead: ptr(true), + DeathDeclarationDelay: &minute, Errors: evmcfg.ClientErrors{ NonceTooLow: ptr[string]("(: |^)nonce too low"), NonceTooHigh: ptr[string]("(: |^)nonce too high"), @@ -990,6 +994,7 @@ NoNewHeadsThreshold = '1m0s' OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418' RPCDefaultBatchSize = 17 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 16 [EVM.Transactions] ForwardersEnabled = true @@ -1060,6 +1065,8 @@ SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = true FinalizedBlockPollInterval = '1s' +EnforceRepeatableRead = true +DeathDeclarationDelay = '1m0s' [EVM.NodePool.Errors] NonceTooLow = '(: |^)nonce too low' @@ -1257,7 +1264,7 @@ func TestConfig_Validate(t *testing.T) { toml string exp string }{ - {name: "invalid", toml: invalidTOML, exp: `invalid configuration: 7 errors: + {name: "invalid", toml: invalidTOML, exp: `invalid configuration: 8 errors: - P2P.V2.Enabled: invalid value (false): P2P required for OCR or OCR2. Please enable P2P or disable OCR/OCR2. - Database.Lock.LeaseRefreshInterval: invalid value (6s): must be less than or equal to half of LeaseDuration (10s) - WebServer: 8 errors: @@ -1287,10 +1294,11 @@ func TestConfig_Validate(t *testing.T) { - WSURL: missing: required for primary nodes - HTTPURL: missing: required for all nodes - 1.HTTPURL: missing: required for all nodes - - 1: 9 errors: + - 1: 10 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - ChainType: invalid value (Foo): must be one of arbitrum, celo, gnosis, kroma, metis, optimismBedrock, scroll, wemix, xlayer, zkevm, zksync or omitted + - HeadTracker.HistoryDepth: invalid value (30): must be greater than or equal to FinalizedBlockOffset - GasEstimator.BumpThreshold: invalid value (0): cannot be 0 if auto-purge feature is enabled for Foo - Transactions.AutoPurge.Threshold: missing: needs to be set if auto-purge feature is enabled for Foo - Transactions.AutoPurge.MinAttempts: missing: needs to be set if auto-purge feature is enabled for Foo @@ -1349,7 +1357,8 @@ func TestConfig_Validate(t *testing.T) { - 0.ChainID: missing: required for all chains - 1: 2 errors: - ChainID: missing: required for all chains - - Nodes: missing: must have at least one node`}, + - Nodes: missing: must have at least one node + - Aptos.0.Enabled: invalid value (1): expected *bool`}, } { t.Run(tt.name, func(t *testing.T) { var c Config diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index c7e224f4f2a..6c11a1fe3a0 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -46,6 +46,24 @@ func (_m *GeneralConfig) AppID() uuid.UUID { return r0 } +// AptosEnabled provides a mock function with given fields: +func (_m *GeneralConfig) AptosEnabled() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for AptosEnabled") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // AuditLogger provides a mock function with given fields: func (_m *GeneralConfig) AuditLogger() config.AuditLogger { ret := _m.Called() diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index fd51d523576..c041a2857b4 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -287,6 +287,7 @@ NoNewHeadsThreshold = '1m0s' OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418' RPCDefaultBatchSize = 17 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 16 [EVM.Transactions] ForwardersEnabled = true @@ -357,6 +358,8 @@ SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = true FinalizedBlockPollInterval = '1s' +EnforceRepeatableRead = true +DeathDeclarationDelay = '1m0s' [EVM.NodePool.Errors] NonceTooLow = '(: |^)nonce too low' diff --git a/core/services/chainlink/testdata/config-invalid.toml b/core/services/chainlink/testdata/config-invalid.toml index 68feeeb0451..ca22e68c22c 100644 --- a/core/services/chainlink/testdata/config-invalid.toml +++ b/core/services/chainlink/testdata/config-invalid.toml @@ -53,6 +53,7 @@ SendOnly = true ChainID = '1' ChainType = 'Foo' FinalityDepth = 32 +FinalizedBlockOffset = 64 [EVM.Transactions.AutoPurge] Enabled = true @@ -158,6 +159,9 @@ APIKey = 'key' [[Starknet]] +[[Aptos]] +Enabled = 1 + [OCR2] Enabled = true diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 13aac2db7fa..22a49476dc4 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -274,6 +274,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 12 [EVM.Transactions] ForwardersEnabled = false @@ -328,6 +329,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 @@ -370,6 +373,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -424,6 +428,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 @@ -460,6 +466,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -514,6 +521,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 diff --git a/core/services/chainlink/testdata/config-multi-chain.toml b/core/services/chainlink/testdata/config-multi-chain.toml index e45255a4373..5373e0e62d3 100644 --- a/core/services/chainlink/testdata/config-multi-chain.toml +++ b/core/services/chainlink/testdata/config-multi-chain.toml @@ -39,6 +39,7 @@ CPUProfileRate = 7 ChainID = '1' FinalityDepth = 26 FinalityTagEnabled = false +FinalizedBlockOffset = 12 [[EVM.Nodes]] Name = 'primary' diff --git a/core/services/cron/cron.go b/core/services/cron/cron.go index 500192554fb..aa4d1d782f1 100644 --- a/core/services/cron/cron.go +++ b/core/services/cron/cron.go @@ -32,6 +32,9 @@ func NewCronFromJobSpec( "jobID", jobSpec.ID, "schedule", jobSpec.CronSpec.CronSchedule, ) + if id := jobSpec.CronSpec.EVMChainID; id != nil { + cronLogger = logger.With("evmChainID", id) + } return &Cron{ cronRunner: cronRunner(), @@ -48,7 +51,7 @@ func (cr *Cron) Start(context.Context) error { _, err := cr.cronRunner.AddFunc(cr.jobSpec.CronSpec.CronSchedule, cr.runPipeline) if err != nil { - cr.logger.Errorw(fmt.Sprintf("Error running cron job %d", cr.jobSpec.ID), "err", err, "schedule", cr.jobSpec.CronSpec.CronSchedule, "jobID", cr.jobSpec.ID) + cr.logger.Errorw(fmt.Sprintf("Error running cron job %d", cr.jobSpec.ID), "err", err) return err } cr.cronRunner.Start() @@ -67,12 +70,17 @@ func (cr *Cron) runPipeline() { ctx, cancel := cr.chStop.NewCtx() defer cancel() + jobSpec := map[string]interface{}{ + "databaseID": cr.jobSpec.ID, + "externalJobID": cr.jobSpec.ExternalJobID, + "name": cr.jobSpec.Name.ValueOrZero(), + } + if id := cr.jobSpec.CronSpec.EVMChainID; id != nil { + jobSpec["evmChainID"] = id.String() + } + vars := pipeline.NewVarsFrom(map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "databaseID": cr.jobSpec.ID, - "externalJobID": cr.jobSpec.ExternalJobID, - "name": cr.jobSpec.Name.ValueOrZero(), - }, + "jobSpec": jobSpec, "jobRun": map[string]interface{}{ "meta": map[string]interface{}{}, }, diff --git a/core/services/feeds/mocks/connections_manager.go b/core/services/feeds/mocks/connections_manager.go index 06cb0eeb5aa..daeb06f6922 100644 --- a/core/services/feeds/mocks/connections_manager.go +++ b/core/services/feeds/mocks/connections_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/feeds_manager_client.go b/core/services/feeds/mocks/feeds_manager_client.go index 71c8786da3e..e2b92c28a85 100644 --- a/core/services/feeds/mocks/feeds_manager_client.go +++ b/core/services/feeds/mocks/feeds_manager_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index 625a0b41d9a..3fce89eb60a 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index 1e2e6393276..de5779374a9 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go index ac67c353cfb..0e969294b90 100644 --- a/core/services/fluxmonitorv2/mocks/contract_submitter.go +++ b/core/services/fluxmonitorv2/mocks/contract_submitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go index 0585611ed03..7b5e0330c8b 100644 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ b/core/services/fluxmonitorv2/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index f831c854ce4..4c99cea1af0 100644 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ b/core/services/fluxmonitorv2/mocks/key_store_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go index 7755543b405..d43a9ea16e6 100644 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ b/core/services/fluxmonitorv2/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/bridge_accessor.go b/core/services/functions/mocks/bridge_accessor.go index 797007d7886..3641e7dfa1a 100644 --- a/core/services/functions/mocks/bridge_accessor.go +++ b/core/services/functions/mocks/bridge_accessor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/external_adapter_client.go b/core/services/functions/mocks/external_adapter_client.go index cd402c1e6a5..e7f7053a0b3 100644 --- a/core/services/functions/mocks/external_adapter_client.go +++ b/core/services/functions/mocks/external_adapter_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/functions_listener.go b/core/services/functions/mocks/functions_listener.go index fed369fd659..ed0d269c6f5 100644 --- a/core/services/functions/mocks/functions_listener.go +++ b/core/services/functions/mocks/functions_listener.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/offchain_transmitter.go b/core/services/functions/mocks/offchain_transmitter.go index 1e1422b8d46..b718222d091 100644 --- a/core/services/functions/mocks/offchain_transmitter.go +++ b/core/services/functions/mocks/offchain_transmitter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/functions/mocks/orm.go b/core/services/functions/mocks/orm.go index c921fda5c69..813abed7e23 100644 --- a/core/services/functions/mocks/orm.go +++ b/core/services/functions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/gateway_connector.go b/core/services/gateway/connector/mocks/gateway_connector.go index 0f37ee6040a..41e3148d05a 100644 --- a/core/services/gateway/connector/mocks/gateway_connector.go +++ b/core/services/gateway/connector/mocks/gateway_connector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/gateway_connector_handler.go b/core/services/gateway/connector/mocks/gateway_connector_handler.go index c21528134f7..a79a2d32fed 100644 --- a/core/services/gateway/connector/mocks/gateway_connector_handler.go +++ b/core/services/gateway/connector/mocks/gateway_connector_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/connector/mocks/signer.go b/core/services/gateway/connector/mocks/signer.go index bb4c3648397..c60bd9d4360 100644 --- a/core/services/gateway/connector/mocks/signer.go +++ b/core/services/gateway/connector/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go index 7581414d00f..6d7c6a25357 100644 --- a/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go index c1d47169c51..9c293fb2f4a 100644 --- a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go +++ b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go index 93b476820a4..9bc8fc3ccb4 100644 --- a/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go index 614ba83af17..759cf03c5df 100644 --- a/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/mocks/don.go b/core/services/gateway/handlers/mocks/don.go index 91c162b2f55..ceaa81eea15 100644 --- a/core/services/gateway/handlers/mocks/don.go +++ b/core/services/gateway/handlers/mocks/don.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/handlers/mocks/handler.go b/core/services/gateway/handlers/mocks/handler.go index e22c7f158f3..e0bfe28f630 100644 --- a/core/services/gateway/handlers/mocks/handler.go +++ b/core/services/gateway/handlers/mocks/handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/connection_acceptor.go b/core/services/gateway/network/mocks/connection_acceptor.go index 37ebc7b8c9e..1af874b4334 100644 --- a/core/services/gateway/network/mocks/connection_acceptor.go +++ b/core/services/gateway/network/mocks/connection_acceptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/connection_initiator.go b/core/services/gateway/network/mocks/connection_initiator.go index 7efac288ba8..0b63edf1826 100644 --- a/core/services/gateway/network/mocks/connection_initiator.go +++ b/core/services/gateway/network/mocks/connection_initiator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/http_request_handler.go b/core/services/gateway/network/mocks/http_request_handler.go index 0cbcf3eb6b1..d2bba61f2f9 100644 --- a/core/services/gateway/network/mocks/http_request_handler.go +++ b/core/services/gateway/network/mocks/http_request_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/http_server.go b/core/services/gateway/network/mocks/http_server.go index 586677c604c..8609803eaff 100644 --- a/core/services/gateway/network/mocks/http_server.go +++ b/core/services/gateway/network/mocks/http_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/gateway/network/mocks/web_socket_server.go b/core/services/gateway/network/mocks/web_socket_server.go index fb880193c7e..32483fe4025 100644 --- a/core/services/gateway/network/mocks/web_socket_server.go +++ b/core/services/gateway/network/mocks/web_socket_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 764c517e8e4..6defdeeb614 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -997,6 +997,18 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { require.NoError(t, err) }) + t.Run(("test Aptos key validation"), func(t *testing.T) { + ctx := testutils.Context(t) + jb.OCR2OracleSpec.Relay = relay.NetworkAptos + err := job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, "bad key") + require.EqualError(t, err, "no Aptos key matching: \"bad key\"") + + aptosKey, err := keyStore.Aptos().Create(ctx) + require.NoError(t, err) + err = job.ValidateKeyStoreMatch(ctx, jb.OCR2OracleSpec, keyStore, aptosKey.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 diff --git a/core/services/job/mocks/kv_store.go b/core/services/job/mocks/kv_store.go index 270a6c1d554..dba287da5e7 100644 --- a/core/services/job/mocks/kv_store.go +++ b/core/services/job/mocks/kv_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index e8911b25af3..1d2615b519c 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/service_ctx.go b/core/services/job/mocks/service_ctx.go index d01ef619be3..2871f7fcf07 100644 --- a/core/services/job/mocks/service_ctx.go +++ b/core/services/job/mocks/service_ctx.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/job/mocks/spawner.go b/core/services/job/mocks/spawner.go index 7127636cdbb..24bfa36bec0 100644 --- a/core/services/job/mocks/spawner.go +++ b/core/services/job/mocks/spawner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/job/models.go b/core/services/job/models.go index 5457768141d..a21a43d12dc 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -352,7 +352,7 @@ type ocr2Config interface { SimulateTransactions() bool } -var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions} +var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.OCR2Keeper, types.Functions} // OCR2OracleSpec defines the job spec for OCR2 jobs. // Relay config is chain specific config for a relay (chain adapter). @@ -490,6 +490,7 @@ type DirectRequestSpec struct { type CronSpec struct { ID int32 `toml:"-"` CronSchedule string `toml:"schedule"` + EVMChainID *big.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` } diff --git a/core/services/job/orm.go b/core/services/job/orm.go index efcb0882840..3f2d5c237d7 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -502,8 +502,8 @@ func (o *orm) insertKeeperSpec(ctx context.Context, spec *KeeperSpec) (specID in } func (o *orm) insertCronSpec(ctx context.Context, spec *CronSpec) (specID int32, err error) { - return o.prepareQuerySpecID(ctx, `INSERT INTO cron_specs (cron_schedule, created_at, updated_at) - VALUES (:cron_schedule, NOW(), NOW()) + return o.prepareQuerySpecID(ctx, `INSERT INTO cron_specs (cron_schedule, evm_chain_id, created_at, updated_at) + VALUES (:cron_schedule, :evm_chain_id, NOW(), NOW()) RETURNING id;`, spec) } @@ -602,8 +602,10 @@ func validateKeyStoreMatchForRelay(ctx context.Context, network string, keyStore return errors.Errorf("no Starknet key matching: %q", key) } case relay.NetworkAptos: - // TODO BCI-2953 - return nil + _, err := keyStore.Aptos().Get(key) + if err != nil { + return errors.Errorf("no Aptos key matching: %q", key) + } } return nil } diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 4abb81eda3a..86f0324e6a0 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/capabilities" + "github.com/smartcontractkit/chainlink/v2/plugins" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/plugins" ) type delegate struct { @@ -316,7 +316,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), processConfig) d := ocr2.NewDelegate(nil, orm, nil, nil, nil, nil, nil, monitoringEndpoint, legacyChains, lggr, ocr2DelegateConfig, - keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon, capabilities.NewRegistry(lggr)) + keyStore.OCR2(), ethKeyStore, testRelayGetter, mailMon, capabilities.NewRegistry(lggr)) delegateOCR2 := &delegate{jobOCR2Keeper.Type, []job.ServiceCtx{}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ diff --git a/core/services/keystore/aptos.go b/core/services/keystore/aptos.go new file mode 100644 index 00000000000..4a40033ae0d --- /dev/null +++ b/core/services/keystore/aptos.go @@ -0,0 +1,182 @@ +package keystore + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" +) + +//go:generate mockery --quiet --name Aptos --output ./mocks/ --case=underscore --filename aptos.go + +type Aptos interface { + Get(id string) (aptoskey.Key, error) + GetAll() ([]aptoskey.Key, error) + Create(ctx context.Context) (aptoskey.Key, error) + Add(ctx context.Context, key aptoskey.Key) error + Delete(ctx context.Context, id string) (aptoskey.Key, error) + Import(ctx context.Context, keyJSON []byte, password string) (aptoskey.Key, error) + Export(id string, password string) ([]byte, error) + EnsureKey(ctx context.Context) error + Sign(ctx context.Context, id string, msg []byte) (signature []byte, err error) +} + +type aptos struct { + *keyManager +} + +var _ Aptos = &aptos{} + +func newAptosKeyStore(km *keyManager) *aptos { + return &aptos{ + km, + } +} + +func (ks *aptos) Get(id string) (aptoskey.Key, error) { + ks.lock.RLock() + defer ks.lock.RUnlock() + if ks.isLocked() { + return aptoskey.Key{}, ErrLocked + } + return ks.getByID(id) +} + +func (ks *aptos) GetAll() (keys []aptoskey.Key, _ error) { + ks.lock.RLock() + defer ks.lock.RUnlock() + if ks.isLocked() { + return nil, ErrLocked + } + for _, key := range ks.keyRing.Aptos { + keys = append(keys, key) + } + return keys, nil +} + +func (ks *aptos) Create(ctx context.Context) (aptoskey.Key, error) { + ks.lock.Lock() + defer ks.lock.Unlock() + if ks.isLocked() { + return aptoskey.Key{}, ErrLocked + } + key, err := aptoskey.New() + if err != nil { + return aptoskey.Key{}, err + } + return key, ks.safeAddKey(ctx, key) +} + +func (ks *aptos) Add(ctx context.Context, key aptoskey.Key) error { + ks.lock.Lock() + defer ks.lock.Unlock() + if ks.isLocked() { + return ErrLocked + } + if _, found := ks.keyRing.Aptos[key.ID()]; found { + return fmt.Errorf("key with ID %s already exists", key.ID()) + } + return ks.safeAddKey(ctx, key) +} + +func (ks *aptos) Delete(ctx context.Context, id string) (aptoskey.Key, error) { + ks.lock.Lock() + defer ks.lock.Unlock() + if ks.isLocked() { + return aptoskey.Key{}, ErrLocked + } + key, err := ks.getByID(id) + if err != nil { + return aptoskey.Key{}, err + } + err = ks.safeRemoveKey(ctx, key) + return key, err +} + +func (ks *aptos) Import(ctx context.Context, keyJSON []byte, password string) (aptoskey.Key, error) { + ks.lock.Lock() + defer ks.lock.Unlock() + if ks.isLocked() { + return aptoskey.Key{}, ErrLocked + } + key, err := aptoskey.FromEncryptedJSON(keyJSON, password) + if err != nil { + return aptoskey.Key{}, errors.Wrap(err, "AptosKeyStore#ImportKey failed to decrypt key") + } + if _, found := ks.keyRing.Aptos[key.ID()]; found { + return aptoskey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) + } + return key, ks.keyManager.safeAddKey(ctx, key) +} + +func (ks *aptos) Export(id string, password string) ([]byte, error) { + ks.lock.RLock() + defer ks.lock.RUnlock() + if ks.isLocked() { + return nil, ErrLocked + } + key, err := ks.getByID(id) + if err != nil { + return nil, err + } + return key.ToEncryptedJSON(password, ks.scryptParams) +} + +func (ks *aptos) EnsureKey(ctx context.Context) error { + ks.lock.Lock() + defer ks.lock.Unlock() + if ks.isLocked() { + return ErrLocked + } + if len(ks.keyRing.Aptos) > 0 { + return nil + } + + key, err := aptoskey.New() + if err != nil { + return err + } + + ks.logger.Infof("Created Aptos key with ID %s", key.ID()) + + return ks.safeAddKey(ctx, key) +} + +func (ks *aptos) Sign(_ context.Context, id string, msg []byte) (signature []byte, err error) { + k, err := ks.Get(id) + if err != nil { + return nil, err + } + return k.Sign(msg) +} + +func (ks *aptos) getByID(id string) (aptoskey.Key, error) { + key, found := ks.keyRing.Aptos[id] + if !found { + return aptoskey.Key{}, KeyNotFoundError{ID: id, KeyType: "Aptos"} + } + return key, nil +} + +// AptosSigner implements [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and the requirements +// Handles signing for Apots Messages +type AptosLooppSigner struct { + Aptos +} + +var _ loop.Keystore = &AptosLooppSigner{} + +// Returns a list of Aptos Public Keys +func (s *AptosLooppSigner) Accounts(ctx context.Context) (accounts []string, err error) { + ks, err := s.GetAll() + if err != nil { + return nil, err + } + for _, k := range ks { + accounts = append(accounts, k.ID()) + } + return +} diff --git a/core/services/keystore/dkgencrypt_test.go b/core/services/keystore/aptos_test.go similarity index 70% rename from core/services/keystore/dkgencrypt_test.go rename to core/services/keystore/aptos_test.go index 4856473a0df..9a2764adff6 100644 --- a/core/services/keystore/dkgencrypt_test.go +++ b/core/services/keystore/aptos_test.go @@ -7,25 +7,23 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" ) -func Test_DKGEncryptKeyStore_E2E(t *testing.T) { +func Test_AptosKeyStore_E2E(t *testing.T) { db := pgtest.NewSqlxDB(t) + keyStore := keystore.ExposedNewMaster(t, db) require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) - ks := keyStore.DKGEncrypt() - - assert.NotNil(t, ks) - + ks := keyStore.Aptos() reset := func() { ctx := context.Background() // Executed on cleanup - _, err := db.Exec("DELETE FROM encrypted_key_rings") - require.NoError(t, err) + require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) keyStore.ResetXXXTestOnly() require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) } @@ -60,12 +58,18 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { require.NoError(t, err) exportJSON, err := ks.Export(key.ID(), cltest.Password) require.NoError(t, err) + _, err = ks.Export("non-existent", cltest.Password) + assert.Error(t, err) _, err = ks.Delete(ctx, key.ID()) require.NoError(t, err) _, err = ks.Get(key.ID()) require.Error(t, err) importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) require.NoError(t, err) + _, err = ks.Import(ctx, exportJSON, cltest.Password) + assert.Error(t, err) + _, err = ks.Import(ctx, []byte(""), cltest.Password) + assert.Error(t, err) require.Equal(t, key.ID(), importedKey.ID()) retrievedKey, err := ks.Get(key.ID()) require.NoError(t, err) @@ -75,15 +79,19 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { t.Run("adds an externally created key / deletes a key", func(t *testing.T) { defer reset() ctx := testutils.Context(t) - newKey, err := dkgencryptkey.New() + newKey, err := aptoskey.New() require.NoError(t, err) err = ks.Add(ctx, newKey) require.NoError(t, err) + err = ks.Add(ctx, newKey) + assert.Error(t, err) keys, err := ks.GetAll() require.NoError(t, err) require.Equal(t, 1, len(keys)) _, err = ks.Delete(ctx, newKey.ID()) require.NoError(t, err) + _, err = ks.Delete(ctx, newKey.ID()) + assert.Error(t, err) keys, err = ks.GetAll() require.NoError(t, err) require.Equal(t, 0, len(keys)) @@ -91,40 +99,40 @@ func Test_DKGEncryptKeyStore_E2E(t *testing.T) { require.Error(t, err) }) - t.Run("adds an externally created key/ensures it already exists", func(t *testing.T) { + t.Run("ensures key", func(t *testing.T) { defer reset() ctx := testutils.Context(t) - - newKey, err := dkgencryptkey.New() - assert.NoError(t, err) - err = ks.Add(ctx, newKey) + err := ks.EnsureKey(ctx) assert.NoError(t, err) - err = keyStore.DKGEncrypt().EnsureKey(ctx) + err = ks.EnsureKey(ctx) assert.NoError(t, err) - keys, err2 := ks.GetAll() - assert.NoError(t, err2) + keys, err := ks.GetAll() + require.NoError(t, err) require.Equal(t, 1, len(keys)) - require.Equal(t, newKey.ID(), keys[0].ID()) - require.Equal(t, newKey.PublicKey, keys[0].PublicKey) }) - t.Run("auto creates a key if it doesn't exists when trying to ensure it already exists", func(t *testing.T) { + t.Run("sign tx", func(t *testing.T) { defer reset() ctx := testutils.Context(t) + newKey, err := aptoskey.New() + require.NoError(t, err) + require.NoError(t, ks.Add(ctx, newKey)) - keys, err := ks.GetAll() - assert.NoError(t, err) - assert.Equal(t, 0, len(keys)) - - err = keyStore.DKGEncrypt().EnsureKey(ctx) - assert.NoError(t, err) + // sign unknown ID + _, err = ks.Sign(testutils.Context(t), "not-real", nil) + assert.Error(t, err) - keys, err = ks.GetAll() - assert.NoError(t, err) + // sign known key + payload := []byte{1} + sig, err := ks.Sign(testutils.Context(t), newKey.ID(), payload) + require.NoError(t, err) + directSig, err := newKey.Sign(payload) require.NoError(t, err) - require.Equal(t, 1, len(keys)) + + // signatures should match using keystore sign or key sign + assert.Equal(t, directSig, sig) }) } diff --git a/core/services/keystore/chaintype/chaintype.go b/core/services/keystore/chaintype/chaintype.go index cd149e390ef..8a12322ebfe 100644 --- a/core/services/keystore/chaintype/chaintype.go +++ b/core/services/keystore/chaintype/chaintype.go @@ -19,6 +19,8 @@ const ( Solana ChainType = "solana" // StarkNet for the StarkNet chain StarkNet ChainType = "starknet" + // Aptos for the Aptos chain + Aptos ChainType = "aptos" ) type ChainTypes []ChainType @@ -35,7 +37,7 @@ func (c ChainTypes) String() (out string) { } // SupportedChainTypes contain all chains that are supported -var SupportedChainTypes = ChainTypes{EVM, Cosmos, Solana, StarkNet} +var SupportedChainTypes = ChainTypes{EVM, Cosmos, Solana, StarkNet, Aptos} // ErrInvalidChainType is an error to indicate an unsupported chain type var ErrInvalidChainType error diff --git a/core/services/keystore/dkgencrypt.go b/core/services/keystore/dkgencrypt.go deleted file mode 100644 index 15d0ae8b24d..00000000000 --- a/core/services/keystore/dkgencrypt.go +++ /dev/null @@ -1,164 +0,0 @@ -package keystore - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" -) - -//go:generate mockery --quiet --name DKGEncrypt --output mocks/ --case=underscore - -// DKGEncrypt provides encryption keys for the DKG. -type DKGEncrypt interface { - Get(id string) (dkgencryptkey.Key, error) - GetAll() ([]dkgencryptkey.Key, error) - Create(ctx context.Context) (dkgencryptkey.Key, error) - Add(ctx context.Context, key dkgencryptkey.Key) error - Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) - Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) - Export(id string, password string) ([]byte, error) - EnsureKey(ctx context.Context) error -} - -type dkgEncrypt struct { - *keyManager -} - -func newDKGEncryptKeyStore(km *keyManager) *dkgEncrypt { - return &dkgEncrypt{ - keyManager: km, - } -} - -var _ DKGEncrypt = &dkgEncrypt{} - -// Add implements DKGEncrypt -func (d *dkgEncrypt) Add(ctx context.Context, key dkgencryptkey.Key) error { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return ErrLocked - } - return d.safeAddKey(ctx, key) -} - -// Create implements DKGEncrypt -func (d *dkgEncrypt) Create(ctx context.Context) (dkgencryptkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgencryptkey.Key{}, ErrLocked - } - key, err := dkgencryptkey.New() - if err != nil { - return dkgencryptkey.Key{}, errors.Wrap(err, "dkgencryptkey.New()") - } - return key, d.safeAddKey(ctx, key) -} - -// Delete implements DKGEncrypt -func (d *dkgEncrypt) Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgencryptkey.Key{}, ErrLocked - } - key, err := d.getByID(id) - if err != nil { - return dkgencryptkey.Key{}, err - } - - err = d.safeRemoveKey(ctx, key) - return key, errors.Wrap(err, "safe remove key") -} - -// EnsureKey implements DKGEncrypt -func (d *dkgEncrypt) EnsureKey(ctx context.Context) error { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return ErrLocked - } - if len(d.keyRing.DKGEncrypt) > 0 { - return nil - } - - key, err := dkgencryptkey.New() - if err != nil { - return errors.Wrap(err, "dkgencryptkey. New()") - } - - d.logger.Infof("Created DKGEncrypt key with ID %s", key.ID()) - - return d.safeAddKey(ctx, key) -} - -// Export implements DKGEncrypt -func (d *dkgEncrypt) Export(id string, password string) ([]byte, error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return nil, ErrLocked - } - key, err := d.getByID(id) - if err != nil { - return nil, err - } - return key.ToEncryptedJSON(password, d.scryptParams) -} - -// Get implements DKGEncrypt -func (d *dkgEncrypt) Get(id string) (keys dkgencryptkey.Key, err error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return dkgencryptkey.Key{}, ErrLocked - } - return d.getByID(id) -} - -// GetAll implements DKGEncrypt -func (d *dkgEncrypt) GetAll() (keys []dkgencryptkey.Key, err error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return nil, ErrLocked - } - for _, key := range d.keyRing.DKGEncrypt { - keys = append(keys, key) - } - return keys, nil -} - -// Import implements DKGEncrypt -func (d *dkgEncrypt) Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgencryptkey.Key{}, ErrLocked - } - key, err := dkgencryptkey.FromEncryptedJSON(keyJSON, password) - if err != nil { - return dkgencryptkey.Key{}, errors.Wrap(err, "from encrypted json") - } - _, err = d.getByID(key.ID()) - if err == nil { - return dkgencryptkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) - } - return key, d.keyManager.safeAddKey(ctx, key) -} - -// caller must hold lock -func (d *dkgEncrypt) getByID(id string) (dkgencryptkey.Key, error) { - key, found := d.keyRing.DKGEncrypt[id] - if !found { - return dkgencryptkey.Key{}, KeyNotFoundError{ - ID: id, - KeyType: "DKGEncrypt", - } - } - return key, nil -} diff --git a/core/services/keystore/dkgsign.go b/core/services/keystore/dkgsign.go deleted file mode 100644 index 385323fc0fa..00000000000 --- a/core/services/keystore/dkgsign.go +++ /dev/null @@ -1,164 +0,0 @@ -package keystore - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" -) - -//go:generate mockery --quiet --name DKGSign --output mocks/ --case=underscore - -// DKGSign provides signing keys for the DKG. -type DKGSign interface { - Get(id string) (dkgsignkey.Key, error) - GetAll() ([]dkgsignkey.Key, error) - Create(ctx context.Context) (dkgsignkey.Key, error) - Add(ctx context.Context, key dkgsignkey.Key) error - Delete(ctx context.Context, id string) (dkgsignkey.Key, error) - Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) - Export(id string, password string) ([]byte, error) - EnsureKey(ctx context.Context) error -} - -type dkgSign struct { - *keyManager -} - -func newDKGSignKeyStore(km *keyManager) *dkgSign { - return &dkgSign{ - keyManager: km, - } -} - -var _ DKGSign = &dkgSign{} - -// Add implements DKGSign -func (d *dkgSign) Add(ctx context.Context, key dkgsignkey.Key) error { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return ErrLocked - } - return d.safeAddKey(ctx, key) -} - -// Create implements DKGSign -func (d *dkgSign) Create(ctx context.Context) (dkgsignkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgsignkey.Key{}, ErrLocked - } - key, err := dkgsignkey.New() - if err != nil { - return dkgsignkey.Key{}, errors.Wrap(err, "dkgsignkey New()") - } - return key, d.safeAddKey(ctx, key) -} - -// Delete implements DKGSign -func (d *dkgSign) Delete(ctx context.Context, id string) (dkgsignkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgsignkey.Key{}, ErrLocked - } - key, err := d.getByID(id) - if err != nil { - return dkgsignkey.Key{}, err - } - - err = d.safeRemoveKey(ctx, key) - return key, errors.Wrap(err, "safe remove key") -} - -// EnsureKey implements DKGSign -func (d *dkgSign) EnsureKey(ctx context.Context) error { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return ErrLocked - } - if len(d.keyRing.DKGSign) > 0 { - return nil - } - - key, err := dkgsignkey.New() - if err != nil { - return errors.Wrap(err, "dkgsignkey New()") - } - - d.logger.Infof("Created DKGSign key with ID %s", key.ID()) - - return d.safeAddKey(ctx, key) -} - -// Export implements DKGSign -func (d *dkgSign) Export(id string, password string) ([]byte, error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return nil, ErrLocked - } - key, err := d.getByID(id) - if err != nil { - return nil, err - } - return key.ToEncryptedJSON(password, d.scryptParams) -} - -// Get implements DKGSign -func (d *dkgSign) Get(id string) (keys dkgsignkey.Key, err error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return dkgsignkey.Key{}, ErrLocked - } - return d.getByID(id) -} - -// GetAll implements DKGSign -func (d *dkgSign) GetAll() (keys []dkgsignkey.Key, err error) { - d.lock.RLock() - defer d.lock.RUnlock() - if d.isLocked() { - return nil, ErrLocked - } - for _, key := range d.keyRing.DKGSign { - keys = append(keys, key) - } - return keys, nil -} - -// Import implements DKGSign -func (d *dkgSign) Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) { - d.lock.Lock() - defer d.lock.Unlock() - if d.isLocked() { - return dkgsignkey.Key{}, ErrLocked - } - key, err := dkgsignkey.FromEncryptedJSON(keyJSON, password) - if err != nil { - return dkgsignkey.Key{}, errors.Wrap(err, "from encrypted json") - } - _, err = d.getByID(key.ID()) - if err == nil { - return dkgsignkey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID()) - } - return key, d.keyManager.safeAddKey(ctx, key) -} - -// caller must hold lock -func (d *dkgSign) getByID(id string) (dkgsignkey.Key, error) { - key, found := d.keyRing.DKGSign[id] - if !found { - return dkgsignkey.Key{}, KeyNotFoundError{ - ID: id, - KeyType: "DKGSign", - } - } - return key, nil -} diff --git a/core/services/keystore/dkgsign_test.go b/core/services/keystore/dkgsign_test.go deleted file mode 100644 index 8aa8cb1ad74..00000000000 --- a/core/services/keystore/dkgsign_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package keystore_test - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" -) - -func Test_DKGSignKeyStore_E2E(t *testing.T) { - db := pgtest.NewSqlxDB(t) - keyStore := keystore.ExposedNewMaster(t, db) - require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password)) - ks := keyStore.DKGSign() - - assert.NotNil(t, ks) - - reset := func() { - ctx := context.Background() // Executed on cleanup - _, err := db.Exec("DELETE FROM encrypted_key_rings") - require.NoError(t, err) - keyStore.ResetXXXTestOnly() - require.NoError(t, keyStore.Unlock(ctx, cltest.Password)) - } - - t.Run("initializes with an empty state", func(t *testing.T) { - defer reset() - keys, err := ks.GetAll() - require.NoError(t, err) - require.Equal(t, 0, len(keys)) - }) - - t.Run("errors when getting non-existent ID", func(t *testing.T) { - defer reset() - _, err := ks.Get("non-existent-id") - require.Error(t, err) - }) - - t.Run("creates a key", func(t *testing.T) { - defer reset() - ctx := testutils.Context(t) - key, err := ks.Create(ctx) - require.NoError(t, err) - retrievedKey, err := ks.Get(key.ID()) - require.NoError(t, err) - require.Equal(t, key, retrievedKey) - }) - - t.Run("imports and exports a key", func(t *testing.T) { - defer reset() - ctx := testutils.Context(t) - key, err := ks.Create(ctx) - require.NoError(t, err) - exportJSON, err := ks.Export(key.ID(), cltest.Password) - require.NoError(t, err) - _, err = ks.Delete(ctx, key.ID()) - require.NoError(t, err) - _, err = ks.Get(key.ID()) - require.Error(t, err) - importedKey, err := ks.Import(ctx, exportJSON, cltest.Password) - require.NoError(t, err) - require.Equal(t, key.ID(), importedKey.ID()) - retrievedKey, err := ks.Get(key.ID()) - require.NoError(t, err) - require.Equal(t, importedKey, retrievedKey) - }) - - t.Run("adds an externally created key / deletes a key", func(t *testing.T) { - defer reset() - ctx := testutils.Context(t) - newKey, err := dkgsignkey.New() - require.NoError(t, err) - err = ks.Add(ctx, newKey) - require.NoError(t, err) - keys, err := ks.GetAll() - require.NoError(t, err) - require.Equal(t, 1, len(keys)) - _, err = ks.Delete(ctx, newKey.ID()) - require.NoError(t, err) - keys, err = ks.GetAll() - require.NoError(t, err) - require.Equal(t, 0, len(keys)) - _, err = ks.Get(newKey.ID()) - require.Error(t, err) - }) - - t.Run("adds an externally created key/ensures it already exists", func(t *testing.T) { - defer reset() - ctx := testutils.Context(t) - newKey, err := dkgsignkey.New() - assert.NoError(t, err) - err = ks.Add(ctx, newKey) - assert.NoError(t, err) - - err = keyStore.DKGSign().EnsureKey(ctx) - assert.NoError(t, err) - keys, err2 := ks.GetAll() - assert.NoError(t, err2) - - require.Equal(t, 1, len(keys)) - require.Equal(t, newKey.ID(), keys[0].ID()) - require.Equal(t, newKey.PublicKey, keys[0].PublicKey) - }) - - t.Run("auto creates a key if it doesn't exists when trying to ensure it already exists", func(t *testing.T) { - defer reset() - ctx := testutils.Context(t) - - keys, err := ks.GetAll() - assert.NoError(t, err) - assert.Equal(t, 0, len(keys)) - - err = keyStore.DKGSign().EnsureKey(ctx) - assert.NoError(t, err) - - keys, err = ks.GetAll() - assert.NoError(t, err) - - require.NoError(t, err) - require.Equal(t, 1, len(keys)) - }) -} diff --git a/core/services/keystore/keys/aptoskey/account.go b/core/services/keystore/keys/aptoskey/account.go new file mode 100644 index 00000000000..89f62d33011 --- /dev/null +++ b/core/services/keystore/keys/aptoskey/account.go @@ -0,0 +1,72 @@ +package aptoskey + +import ( + "encoding/hex" + "errors" + "fmt" + "strings" +) + +// AccountAddress is a 32 byte address on the Aptos blockchain +// It can represent an Object, an Account, and much more. +// +// AccountAddress is copied from the aptos sdk because: +// 1. There are still breaking changes in sdk and we don't want the dependency. +// 2. AccountAddress is just a wrapper and can be easily extracted out. +// +// https://github.com/aptos-labs/aptos-go-sdk/blob/main/internal/types/account.go +type AccountAddress [32]byte + +// IsSpecial Returns whether the address is a "special" address. Addresses are considered +// special if the first 63 characters of the hex string are zero. In other words, +// an address is special if the first 31 bytes are zero and the last byte is +// smaller than `0b10000` (16). In other words, special is defined as an address +// that matches the following regex: `^0x0{63}[0-9a-f]$`. In short form this means +// the addresses in the range from `0x0` to `0xf` (inclusive) are special. +// For more details see the v1 address standard defined as part of AIP-40: +// https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md +func (aa *AccountAddress) IsSpecial() bool { + for _, b := range aa[:31] { + if b != 0 { + return false + } + } + return aa[31] < 0x10 +} + +// String Returns the canonical string representation of the AccountAddress +func (aa *AccountAddress) String() string { + if aa.IsSpecial() { + return fmt.Sprintf("0x%x", aa[31]) + } + return BytesToHex(aa[:]) +} + +// ParseStringRelaxed parses a string into an AccountAddress +func (aa *AccountAddress) ParseStringRelaxed(x string) error { + x = strings.TrimPrefix(x, "0x") + if len(x) < 1 { + return ErrAddressTooShort + } + if len(x) > 64 { + return ErrAddressTooLong + } + if len(x)%2 != 0 { + x = "0" + x + } + bytes, err := hex.DecodeString(x) + if err != nil { + return err + } + // zero-prefix/right-align what bytes we got + copy((*aa)[32-len(bytes):], bytes) + + return nil +} + +var ErrAddressTooShort = errors.New("AccountAddress too short") +var ErrAddressTooLong = errors.New("AccountAddress too long") + +func BytesToHex(bytes []byte) string { + return "0x" + hex.EncodeToString(bytes) +} diff --git a/core/services/keystore/keys/aptoskey/account_test.go b/core/services/keystore/keys/aptoskey/account_test.go new file mode 100644 index 00000000000..b9ed4ea04a5 --- /dev/null +++ b/core/services/keystore/keys/aptoskey/account_test.go @@ -0,0 +1,141 @@ +package aptoskey + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// Tests extracted from +// https://github.com/aptos-labs/aptos-go-sdk/blob/5ee5ac308e5881b508c0a5124f5e0b8df27a4d40/internal/types/account_test.go + +func TestStringOutput(t *testing.T) { + inputs := [][]byte{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F}, + {0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0x02, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0x00, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0x00, 0x04, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + {0x00, 0x00, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + } + expected := []string{ + "0x0", + "0x1", + "0xf", + "0x1234123412341234123412341234123412341234123412340123456789abcdef", + "0x0234123412341234123412341234123412341234123412340123456789abcdef", + "0x0034123412341234123412341234123412341234123412340123456789abcdef", + "0x0004123412341234123412341234123412341234123412340123456789abcdef", + "0x0000123412341234123412341234123412341234123412340123456789abcdef", + } + + for i := 0; i < len(inputs); i++ { + addr := AccountAddress(inputs[i]) + assert.Equal(t, expected[i], addr.String()) + } +} + +func TestAccountAddress_ParseStringRelaxed_Error(t *testing.T) { + var owner AccountAddress + err := owner.ParseStringRelaxed("0x") + assert.Error(t, err) + err = owner.ParseStringRelaxed("0xF1234567812345678123456781234567812345678123456781234567812345678") + assert.Error(t, err) + err = owner.ParseStringRelaxed("NotHex") + assert.Error(t, err) +} + +func TestAccountAddress_String(t *testing.T) { + testCases := []struct { + name string + address AccountAddress + expected string + }{ + { + name: "Special address", + address: AccountAddress{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + expected: "0x1", + }, + { + name: "Non-special address", + address: AccountAddress{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + expected: "0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, tc.address.String()) + }) + } +} + +func TestAccountAddress_IsSpecial(t *testing.T) { + testCases := []struct { + name string + address AccountAddress + expected bool + }{ + { + name: "Special address", + address: AccountAddress{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + expected: true, + }, + { + name: "Non-special address", + address: AccountAddress{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + expected: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, tc.address.IsSpecial()) + }) + } +} + +func TestBytesToHex(t *testing.T) { + testCases := []struct { + name string + bytes []byte + expected string + }{ + { + name: "Empty bytes", + bytes: []byte{}, + expected: "0x", + }, + { + name: "Non-empty bytes", + bytes: []byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, + expected: "0x123456789abcdef0", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, BytesToHex(tc.bytes)) + }) + } +} + +func TestAccountSpecialString(t *testing.T) { + var aa AccountAddress + aa[31] = 3 + aas := aa.String() + if aas != "0x3" { + t.Errorf("wanted 0x3 got %s", aas) + } + + var aa2 AccountAddress + err := aa2.ParseStringRelaxed("0x3") + if err != nil { + t.Errorf("unexpected err %s", err) + } + if aa2 != aa { + t.Errorf("aa2 != aa") + } +} diff --git a/core/services/keystore/keys/dkgsignkey/export.go b/core/services/keystore/keys/aptoskey/export.go similarity index 74% rename from core/services/keystore/keys/dkgsignkey/export.go rename to core/services/keystore/keys/aptoskey/export.go index 3c421760d63..23553ef9dca 100644 --- a/core/services/keystore/keys/dkgsignkey/export.go +++ b/core/services/keystore/keys/aptoskey/export.go @@ -1,15 +1,17 @@ -package dkgsignkey +package aptoskey import ( + "encoding/hex" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -const keyTypeIdentifier = "DKGSign" +const keyTypeIdentifier = "Aptos" -// FromEncryptedJSON returns a dkgsignkey.Key from encrypted data in go-ethereum keystore format. +// FromEncryptedJSON gets key from json and password func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { return keys.FromEncryptedJSON( keyTypeIdentifier, @@ -22,7 +24,7 @@ func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { ) } -// ToEncryptedJSON exports this key into a JSON object following the format of EncryptedDKGSignKeyExport +// ToEncryptedJSON returns encrypted JSON representing key func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) (export []byte, err error) { return keys.ToEncryptedJSON( keyTypeIdentifier, @@ -34,7 +36,7 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, - PublicKey: key.PublicKeyString(), + PublicKey: hex.EncodeToString(key.pubKey), Crypto: cryptoJSON, } }, @@ -42,5 +44,5 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) } func adulteratedPassword(password string) string { - return "dkgsignkey" + password + return "aptoskey" + password } diff --git a/core/services/keystore/keys/dkgsignkey/export_test.go b/core/services/keystore/keys/aptoskey/export_test.go similarity index 83% rename from core/services/keystore/keys/dkgsignkey/export_test.go rename to core/services/keystore/keys/aptoskey/export_test.go index 90d8f66ab38..a920e432298 100644 --- a/core/services/keystore/keys/dkgsignkey/export_test.go +++ b/core/services/keystore/keys/aptoskey/export_test.go @@ -1,4 +1,4 @@ -package dkgsignkey +package aptoskey import ( "testing" @@ -6,7 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" ) -func TestDKGSignKeys_ExportImport(t *testing.T) { +func TestAptosKeys_ExportImport(t *testing.T) { keys.RunKeyExportImportTestcase(t, createKey, decryptKey) } diff --git a/core/services/keystore/keys/aptoskey/key.go b/core/services/keystore/keys/aptoskey/key.go new file mode 100644 index 00000000000..ec9b27a3596 --- /dev/null +++ b/core/services/keystore/keys/aptoskey/key.go @@ -0,0 +1,103 @@ +package aptoskey + +import ( + "crypto" + "crypto/ed25519" + crypto_rand "crypto/rand" + "fmt" + "io" + + "github.com/mr-tron/base58" +) + +// Raw represents the Aptos private key +type Raw []byte + +// Key gets the Key +func (raw Raw) Key() Key { + privKey := ed25519.NewKeyFromSeed(raw) + pubKey := privKey.Public().(ed25519.PublicKey) + return Key{ + privkey: privKey, + pubKey: pubKey, + } +} + +// String returns description +func (raw Raw) String() string { + return "" +} + +// GoString wraps String() +func (raw Raw) GoString() string { + return raw.String() +} + +var _ fmt.GoStringer = &Key{} + +// Key represents Aptos key +type Key struct { + privkey ed25519.PrivateKey + pubKey ed25519.PublicKey +} + +// New creates new Key +func New() (Key, error) { + return newFrom(crypto_rand.Reader) +} + +// MustNewInsecure return Key if no error +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +// newFrom creates new Key from a provided random reader +func newFrom(reader io.Reader) (Key, error) { + pub, priv, err := ed25519.GenerateKey(reader) + if err != nil { + return Key{}, err + } + return Key{ + privkey: priv, + pubKey: pub, + }, nil +} + +// ID gets Key ID +func (key Key) ID() string { + return key.PublicKeyStr() +} + +// GetPublic get Key's public key +func (key Key) GetPublic() ed25519.PublicKey { + return key.pubKey +} + +// PublicKeyStr return base58 encoded public key +func (key Key) PublicKeyStr() string { + return base58.Encode(key.pubKey) +} + +// Raw returns the seed from private key +func (key Key) Raw() Raw { + return key.privkey.Seed() +} + +// String is the print-friendly format of the Key +func (key Key) String() string { + return fmt.Sprintf("AptosKey{PrivateKey: , Public Key: %s}", key.PublicKeyStr()) +} + +// GoString wraps String() +func (key Key) GoString() string { + return key.String() +} + +// Sign is used to sign a message +func (key Key) Sign(msg []byte) ([]byte, error) { + return key.privkey.Sign(crypto_rand.Reader, msg, crypto.Hash(0)) // no specific hash function used +} diff --git a/core/services/keystore/keys/dkgencryptkey/export.go b/core/services/keystore/keys/dkgencryptkey/export.go deleted file mode 100644 index 3bccf1a07ba..00000000000 --- a/core/services/keystore/keys/dkgencryptkey/export.go +++ /dev/null @@ -1,44 +0,0 @@ -package dkgencryptkey - -import ( - "github.com/ethereum/go-ethereum/accounts/keystore" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -const keyTypeIdentifier = "DKGEncrypt" - -// FromEncryptedJSON returns a dkgencryptkey.KeyV2 from encrypted data in go-ethereum keystore format. -func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { - return keys.FromEncryptedJSON( - keyTypeIdentifier, - keyJSON, - password, - adulteratedPassword, - func(_ keys.EncryptedKeyExport, rawPrivKey []byte) (Key, error) { - return Raw(rawPrivKey).Key(), nil - }) -} - -// ToEncryptedJSON exports this key into a JSON object following the format of EncryptedDKGEncryptKeyExport -func (k Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) (export []byte, err error) { - return keys.ToEncryptedJSON( - keyTypeIdentifier, - k.Raw(), - k, - password, - scryptParams, - adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { - return keys.EncryptedKeyExport{ - KeyType: id, - PublicKey: key.PublicKeyString(), - Crypto: cryptoJSON, - } - }) -} - -func adulteratedPassword(password string) string { - return "dkgencryptkey" + password -} diff --git a/core/services/keystore/keys/dkgencryptkey/export_test.go b/core/services/keystore/keys/dkgencryptkey/export_test.go deleted file mode 100644 index 952c786d8ab..00000000000 --- a/core/services/keystore/keys/dkgencryptkey/export_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package dkgencryptkey - -import ( - "testing" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" -) - -func TestDKGEncryptKeys_ExportImport(t *testing.T) { - keys.RunKeyExportImportTestcase(t, createKey, decryptKey) -} - -func createKey() (keys.KeyType, error) { - return New() -} - -func decryptKey(keyJSON []byte, password string) (keys.KeyType, error) { - return FromEncryptedJSON(keyJSON, password) -} diff --git a/core/services/keystore/keys/dkgencryptkey/key.go b/core/services/keystore/keys/dkgencryptkey/key.go deleted file mode 100644 index e94f2a6bdf4..00000000000 --- a/core/services/keystore/keys/dkgencryptkey/key.go +++ /dev/null @@ -1,116 +0,0 @@ -package dkgencryptkey - -import ( - "encoding/hex" - "fmt" - "math/big" - - "github.com/pkg/errors" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/pairing" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" -) - -var suite pairing.Suite = &altbn_128.PairingSuite{} -var g1 = suite.G1() - -type Raw []byte - -func (r Raw) Key() Key { - scalar := g1.Scalar() - err := scalar.UnmarshalBinary(r) - if err != nil { - panic(err) // should never happen6 - } - key, err := keyFromScalar(scalar) - if err != nil { - panic(err) // should never happen - } - return key -} - -func (r Raw) String() string { - return "" -} - -func (r Raw) GoString() string { - return r.String() -} - -type Key struct { - privateKey kyber.Scalar - publicKeyBytes []byte - PublicKey kyber.Point -} - -// New returns a new dkgencryptkey key -func New() (Key, error) { - return keyFromScalar(g1.Scalar().Pick(suite.RandomStream())) -} - -// MustNewXXXTestingOnly creates a new DKGEncrypt key from the given secret key. -// NOTE: for testing only. -func MustNewXXXTestingOnly(sk *big.Int) Key { - key, err := keyFromScalar(g1.Scalar().SetInt64(sk.Int64())) - if err != nil { - panic(err) - } - return key -} - -var _ fmt.GoStringer = &Key{} - -// GoString implements fmt.GoStringer -func (k Key) GoString() string { - return k.String() -} - -// String returns the string representation of this key -func (k Key) String() string { - return fmt.Sprintf("DKGEncryptKey{PrivateKey: , PublicKey: %s", k.PublicKeyString()) -} - -// ID returns the ID of this key -func (k Key) ID() string { - return k.PublicKeyString() -} - -// PublicKeyString returns the hex representation of this key's public key -func (k Key) PublicKeyString() string { - return hex.EncodeToString(k.publicKeyBytes) -} - -// Raw returns the key raw data -func (k Key) Raw() Raw { - raw, err := k.privateKey.MarshalBinary() - if err != nil { - panic(err) // should never happen - } - return Raw(raw) -} - -// KyberScalar returns the private key as a kyber.Scalar object -func (k Key) KyberScalar() kyber.Scalar { - return g1.Scalar().Set(k.privateKey) -} - -// KyberPoint returns the public key as a kyber.Point object -func (k Key) KyberPoint() kyber.Point { - return g1.Point().Base().Mul(k.privateKey, nil) -} - -// keyFromScalar creates a new dkgencryptkey key from the given scalar. -// the given scalar must be a scalar of the g1 group in the altbn_128 pairing. -func keyFromScalar(k kyber.Scalar) (Key, error) { - publicKey := g1.Point().Base().Mul(k, nil) - publicKeyBytes, err := publicKey.MarshalBinary() - if err != nil { - return Key{}, errors.Wrap(err, "kyber point MarshalBinary") - } - return Key{ - privateKey: k, - PublicKey: publicKey, - publicKeyBytes: publicKeyBytes, - }, nil -} diff --git a/core/services/keystore/keys/dkgencryptkey/key_test.go b/core/services/keystore/keys/dkgencryptkey/key_test.go deleted file mode 100644 index 3bf12772a46..00000000000 --- a/core/services/keystore/keys/dkgencryptkey/key_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package dkgencryptkey - -import ( - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func TestNew(t *testing.T) { - key, err := New() - assert.NoError(t, err) - assert.NotNil(t, key.privateKey) - assert.NotNil(t, key.PublicKey) - assert.NotNil(t, key.publicKeyBytes) -} - -func TestStringers(t *testing.T) { - key := MustNewXXXTestingOnly(big.NewInt(1337)) - assert.Equal(t, "26578c46722826d18dc5f5a954c65c5c78e0d215a465356502ff8f002aff36ef", key.PublicKeyString()) - assert.Equal(t, - "DKGEncryptKey{PrivateKey: , PublicKey: 26578c46722826d18dc5f5a954c65c5c78e0d215a465356502ff8f002aff36ef", - key.String()) - assert.Equal(t, - "DKGEncryptKey{PrivateKey: , PublicKey: 26578c46722826d18dc5f5a954c65c5c78e0d215a465356502ff8f002aff36ef", - key.GoString()) - assert.Equal(t, - "26578c46722826d18dc5f5a954c65c5c78e0d215a465356502ff8f002aff36ef", - key.ID()) -} - -func TestRaw(t *testing.T) { - key := MustNewXXXTestingOnly(big.NewInt(1337)) - rawFromKey := key.Raw() - scalar := g1.Scalar().SetBytes(rawFromKey) - assert.True(t, scalar.Equal(key.privateKey)) - - keyFromRaw := rawFromKey.Key() - assert.True(t, keyFromRaw.privateKey.Equal(key.privateKey)) - - assert.Equal(t, "", rawFromKey.GoString()) - assert.Equal(t, "", rawFromKey.String()) -} - -func TestExportImport(t *testing.T) { - password := "helloworld" - key := MustNewXXXTestingOnly(big.NewInt(1337)) - encryptedJSON, err := key.ToEncryptedJSON(password, utils.DefaultScryptParams) - assert.NoError(t, err) - - decryptedKey, err := FromEncryptedJSON(encryptedJSON, password) - assert.NoError(t, err) - assert.True(t, decryptedKey.privateKey.Equal(key.privateKey)) - assert.True(t, decryptedKey.PublicKey.Equal(key.PublicKey)) - assert.ElementsMatch(t, decryptedKey.publicKeyBytes, key.publicKeyBytes) -} diff --git a/core/services/keystore/keys/dkgsignkey/key.go b/core/services/keystore/keys/dkgsignkey/key.go deleted file mode 100644 index 6ab18810689..00000000000 --- a/core/services/keystore/keys/dkgsignkey/key.go +++ /dev/null @@ -1,92 +0,0 @@ -package dkgsignkey - -import ( - "encoding/hex" - "fmt" - "math/big" - - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/edwards25519" -) - -var suite = edwards25519.NewBlakeSHA256Ed25519() - -// Raw represents a raw dkgsign secret key in little-endian byte order. -type Raw []byte - -// Key returns a Key object from this raw data. -func (r Raw) Key() Key { - privKey := suite.Scalar().SetBytes(r) - key, err := keyFromScalar(privKey) - if err != nil { - panic(err) // should never happen - } - return key -} - -func (r Raw) String() string { - return "" -} - -func (r Raw) GoString() string { - return r.String() -} - -// Key is DKG signing key that conforms to the keystore.Key interface -type Key struct { - privateKey kyber.Scalar - publicKeyBytes []byte - PublicKey kyber.Point -} - -// New creates a new DKGSign key -func New() (Key, error) { - privateKey := suite.Scalar().Pick(suite.RandomStream()) - return keyFromScalar(privateKey) -} - -// MustNewXXXTestingOnly creates a new DKGSign key from the given secret key. -// NOTE: for testing only. -func MustNewXXXTestingOnly(sk *big.Int) Key { - key, err := keyFromScalar(scalarFromBig(sk)) - if err != nil { - panic(err) - } - return key -} - -var _ fmt.GoStringer = &Key{} - -// GoString implements fmt.GoStringer -func (k Key) GoString() string { - return k.String() -} - -// String returns the string representation of this key -func (k Key) String() string { - return fmt.Sprintf("DKGSignKey{PrivateKey: , PublicKey: %s", k.PublicKey) -} - -// ID returns the ID of this key -func (k Key) ID() string { - return k.PublicKeyString() -} - -// PublicKeyString returns the hex representation of this key's public key -func (k Key) PublicKeyString() string { - return hex.EncodeToString(k.publicKeyBytes) -} - -// Raw returns the key raw data -func (k Key) Raw() Raw { - raw, err := k.privateKey.MarshalBinary() - if err != nil { - panic(err) // should never happen - } - return Raw(raw) -} - -// KyberScalar returns the private key as a kyber.Scalar object -func (k Key) KyberScalar() kyber.Scalar { - return suite.Scalar().Set(k.privateKey) -} diff --git a/core/services/keystore/keys/dkgsignkey/key_test.go b/core/services/keystore/keys/dkgsignkey/key_test.go deleted file mode 100644 index 736aca34f64..00000000000 --- a/core/services/keystore/keys/dkgsignkey/key_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package dkgsignkey - -import ( - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func TestNew(t *testing.T) { - key, err := New() - assert.NoError(t, err) - assert.NotNil(t, key.privateKey) - assert.NotNil(t, key.PublicKey) - assert.NotNil(t, key.publicKeyBytes) -} - -func TestStringers(t *testing.T) { - key := MustNewXXXTestingOnly(big.NewInt(1337)) - assert.Equal(t, "becd7a86af89b2f3ffd11fabe897de820b74cd2956c6e047a14e35d090ade17d", key.PublicKeyString()) - assert.Equal(t, - "DKGSignKey{PrivateKey: , PublicKey: becd7a86af89b2f3ffd11fabe897de820b74cd2956c6e047a14e35d090ade17d", - key.String()) - assert.Equal(t, - "DKGSignKey{PrivateKey: , PublicKey: becd7a86af89b2f3ffd11fabe897de820b74cd2956c6e047a14e35d090ade17d", - key.GoString()) - assert.Equal(t, - "becd7a86af89b2f3ffd11fabe897de820b74cd2956c6e047a14e35d090ade17d", - key.ID()) -} - -func TestRaw(t *testing.T) { - key := MustNewXXXTestingOnly(big.NewInt(1337)) - rawFromKey := key.Raw() - scalar := suite.Scalar().SetBytes(rawFromKey) - assert.True(t, scalar.Equal(key.privateKey)) - - keyFromRaw := rawFromKey.Key() - assert.True(t, keyFromRaw.privateKey.Equal(key.privateKey)) - - assert.Equal(t, "", rawFromKey.GoString()) - assert.Equal(t, "", rawFromKey.String()) -} - -func TestExportImport(t *testing.T) { - password := "helloworld" - key := MustNewXXXTestingOnly(big.NewInt(1337)) - encryptedJSON, err := key.ToEncryptedJSON(password, utils.DefaultScryptParams) - assert.NoError(t, err) - - decryptedKey, err := FromEncryptedJSON(encryptedJSON, password) - assert.NoError(t, err) - assert.True(t, decryptedKey.privateKey.Equal(key.privateKey)) - assert.True(t, decryptedKey.PublicKey.Equal(key.PublicKey)) - assert.ElementsMatch(t, decryptedKey.publicKeyBytes, key.publicKeyBytes) -} diff --git a/core/services/keystore/keys/dkgsignkey/utils.go b/core/services/keystore/keys/dkgsignkey/utils.go deleted file mode 100644 index 8b4add1ed1e..00000000000 --- a/core/services/keystore/keys/dkgsignkey/utils.go +++ /dev/null @@ -1,39 +0,0 @@ -package dkgsignkey - -import ( - "math/big" - - "github.com/pkg/errors" - "go.dedis.ch/kyber/v3" -) - -// scalarFromBig creates a kyber.Scalar belonging to the edwards25519 -// kyber suite from a big integer. This is useful for testing. -func scalarFromBig(i *big.Int) kyber.Scalar { - scalar := suite.Scalar() - // big.Int.Bytes() returns a byte slice in big-endian order, - // need to reverse the slice before we SetBytes since - // SetBytes interprets it in little-endian order. - b := i.Bytes() - reverseSliceInPlace(b) - return scalar.SetBytes(b) -} - -func keyFromScalar(k kyber.Scalar) (Key, error) { - publicKey := suite.Point().Base().Mul(k, nil) - publicKeyBytes, err := publicKey.MarshalBinary() - if err != nil { - return Key{}, errors.Wrap(err, "kyber point MarshalBinary") - } - return Key{ - privateKey: k, - PublicKey: publicKey, - publicKeyBytes: publicKeyBytes, - }, nil -} - -func reverseSliceInPlace[T any](elems []T) { - for i := 0; i < len(elems)/2; i++ { - elems[i], elems[len(elems)-i-1] = elems[len(elems)-i-1], elems[i] - } -} diff --git a/core/services/keystore/keys/ocr2key/aptos_keyring.go b/core/services/keystore/keys/ocr2key/aptos_keyring.go new file mode 100644 index 00000000000..51e6c3a9c8f --- /dev/null +++ b/core/services/keystore/keys/ocr2key/aptos_keyring.go @@ -0,0 +1,118 @@ +package ocr2key + +import ( + "crypto/ed25519" + "encoding/binary" + "io" + + "github.com/hdevalence/ed25519consensus" + "github.com/pkg/errors" + "golang.org/x/crypto/blake2s" + + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &aptosKeyring{} + +type aptosKeyring struct { + privKey ed25519.PrivateKey + pubKey ed25519.PublicKey +} + +func newAptosKeyring(material io.Reader) (*aptosKeyring, error) { + pubKey, privKey, err := ed25519.GenerateKey(material) + if err != nil { + return nil, err + } + return &aptosKeyring{pubKey: pubKey, privKey: privKey}, nil +} + +func (akr *aptosKeyring) PublicKey() ocrtypes.OnchainPublicKey { + return []byte(akr.pubKey) +} + +func (akr *aptosKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + rawReportContext := evmutil.RawReportContext(reportCtx) + h, err := blake2s.New256(nil) + if err != nil { + return nil, err + } + reportLen := make([]byte, 4) + binary.BigEndian.PutUint32(reportLen[0:], uint32(len(report))) + h.Write(reportLen[:]) + h.Write(report) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + h.Write(rawReportContext[2][:]) + return h.Sum(nil), nil +} + +func (akr *aptosKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + sigData, err := akr.reportToSigData(reportCtx, report) + if err != nil { + return nil, err + } + return akr.signBlob(sigData) +} + +func (akr *aptosKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + return nil, errors.New("not implemented") +} + +func (akr *aptosKeyring) signBlob(b []byte) ([]byte, error) { + signedMsg := ed25519.Sign(akr.privKey, b) + // match on-chain parsing (first 32 bytes are for pubkey, remaining are for signature) + return utils.ConcatBytes(akr.PublicKey(), signedMsg), nil +} + +func (akr *aptosKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash, err := akr.reportToSigData(reportCtx, report) + if err != nil { + return false + } + return akr.verifyBlob(publicKey, hash, signature) +} + +func (akr *aptosKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + return false +} + +func (akr *aptosKeyring) verifyBlob(pubkey ocrtypes.OnchainPublicKey, b, sig []byte) bool { + // Ed25519 signatures are always 64 bytes and the + // public key (always prefixed, see Sign above) is always, + // 32 bytes, so we always require the max signature length. + if len(sig) != akr.MaxSignatureLength() { + return false + } + if len(pubkey) != ed25519.PublicKeySize { + return false + } + return ed25519consensus.Verify(ed25519.PublicKey(pubkey), b, sig[32:]) +} + +func (akr *aptosKeyring) MaxSignatureLength() int { + // Reference: https://pkg.go.dev/crypto/ed25519 + return ed25519.PublicKeySize + ed25519.SignatureSize // 32 + 64 +} + +func (akr *aptosKeyring) Marshal() ([]byte, error) { + return akr.privKey.Seed(), nil +} + +func (akr *aptosKeyring) Unmarshal(in []byte) error { + if len(in) != ed25519.SeedSize { + return errors.Errorf("unexpected seed size, got %d want %d", len(in), ed25519.SeedSize) + } + privKey := ed25519.NewKeyFromSeed(in) + akr.privKey = privKey + pubKey, ok := privKey.Public().(ed25519.PublicKey) + if !ok { + return errors.New("failed to cast public key to ed25519.PublicKey") + } + akr.pubKey = pubKey + return nil +} diff --git a/core/services/keystore/keys/ocr2key/aptos_keyring_test.go b/core/services/keystore/keys/ocr2key/aptos_keyring_test.go new file mode 100644 index 00000000000..2b88d61065c --- /dev/null +++ b/core/services/keystore/keys/ocr2key/aptos_keyring_test.go @@ -0,0 +1,58 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/require" +) + +func TestAptosKeyRing_Sign_Verify(t *testing.T) { + kr1, err := newAptosKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newAptosKeyring(cryptorand.Reader) + require.NoError(t, err) + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + require.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + require.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + require.False(t, result) + }) +} + +func TestAptosKeyRing_Marshalling(t *testing.T) { + kr1, err := newAptosKeyring(cryptorand.Reader) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := aptosKeyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.True(t, bytes.Equal(kr1.pubKey, kr2.pubKey)) + assert.True(t, bytes.Equal(kr1.privKey, kr2.privKey)) + + // Invalid seed size should error + require.Error(t, kr2.Unmarshal([]byte{0x01})) +} diff --git a/core/services/keystore/keys/ocr2key/cosmos_keyring.go b/core/services/keystore/keys/ocr2key/cosmos_keyring.go index 5f1b9b98198..1d1a477f2d0 100644 --- a/core/services/keystore/keys/ocr2key/cosmos_keyring.go +++ b/core/services/keystore/keys/ocr2key/cosmos_keyring.go @@ -7,12 +7,13 @@ import ( "github.com/hdevalence/ed25519consensus" "github.com/pkg/errors" - "github.com/smartcontractkit/libocr/offchainreporting2/types" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "golang.org/x/crypto/blake2s" "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) var _ ocrtypes.OnchainKeyring = &cosmosKeyring{} @@ -108,6 +109,10 @@ func (ckr *cosmosKeyring) Unmarshal(in []byte) error { } privKey := ed25519.NewKeyFromSeed(in) ckr.privKey = privKey - ckr.pubKey = privKey.Public().(ed25519.PublicKey) + pubKey, ok := privKey.Public().(ed25519.PublicKey) + if !ok { + return errors.New("failed to cast public key to ed25519.PublicKey") + } + ckr.pubKey = pubKey return nil } diff --git a/core/services/keystore/keys/ocr2key/export.go b/core/services/keystore/keys/ocr2key/export.go index 5487e310462..8fa5ffedfed 100644 --- a/core/services/keystore/keys/ocr2key/export.go +++ b/core/services/keystore/keys/ocr2key/export.go @@ -46,6 +46,8 @@ func FromEncryptedJSON(keyJSON []byte, password string) (KeyBundle, error) { kb = newKeyBundle(new(solanaKeyring)) case chaintype.StarkNet: kb = newKeyBundle(new(starkkey.OCR2Key)) + case chaintype.Aptos: + kb = newKeyBundle(new(aptosKeyring)) default: return nil, chaintype.NewErrInvalidChainType(export.ChainType) } diff --git a/core/services/keystore/keys/ocr2key/export_test.go b/core/services/keystore/keys/ocr2key/export_test.go index dfa820eb2be..b0ffa2db009 100644 --- a/core/services/keystore/keys/ocr2key/export_test.go +++ b/core/services/keystore/keys/ocr2key/export_test.go @@ -18,6 +18,7 @@ func TestExport(t *testing.T) { {chain: chaintype.Cosmos}, {chain: chaintype.Solana}, {chain: chaintype.StarkNet}, + {chain: chaintype.Aptos}, } for _, tc := range tt { tc := tc diff --git a/core/services/keystore/keys/ocr2key/key_bundle.go b/core/services/keystore/keys/ocr2key/key_bundle.go index 2c3a4bebeb0..2c25a159fef 100644 --- a/core/services/keystore/keys/ocr2key/key_bundle.go +++ b/core/services/keystore/keys/ocr2key/key_bundle.go @@ -43,6 +43,7 @@ var _ KeyBundle = &keyBundle[*evmKeyring]{} var _ KeyBundle = &keyBundle[*cosmosKeyring]{} var _ KeyBundle = &keyBundle[*solanaKeyring]{} var _ KeyBundle = &keyBundle[*starkkey.OCR2Key]{} +var _ KeyBundle = &keyBundle[*aptosKeyring]{} var curve = secp256k1.S256() @@ -57,6 +58,8 @@ func New(chainType chaintype.ChainType) (KeyBundle, error) { return newKeyBundleRand(chaintype.Solana, newSolanaKeyring) case chaintype.StarkNet: return newKeyBundleRand(chaintype.StarkNet, starkkey.NewOCR2Key) + case chaintype.Aptos: + return newKeyBundleRand(chaintype.Aptos, newAptosKeyring) } return nil, chaintype.NewErrInvalidChainType(chainType) } @@ -72,6 +75,8 @@ func MustNewInsecure(reader io.Reader, chainType chaintype.ChainType) KeyBundle return mustNewKeyBundleInsecure(chaintype.Solana, newSolanaKeyring, reader) case chaintype.StarkNet: return mustNewKeyBundleInsecure(chaintype.StarkNet, starkkey.NewOCR2Key, reader) + case chaintype.Aptos: + return mustNewKeyBundleInsecure(chaintype.Aptos, newAptosKeyring, reader) } panic(chaintype.NewErrInvalidChainType(chainType)) } @@ -121,6 +126,8 @@ func (raw Raw) Key() (kb KeyBundle) { kb = newKeyBundle(new(solanaKeyring)) case chaintype.StarkNet: kb = newKeyBundle(new(starkkey.OCR2Key)) + case chaintype.Aptos: + kb = newKeyBundle(new(aptosKeyring)) default: return nil } diff --git a/core/services/keystore/keys/solkey/key.go b/core/services/keystore/keys/solkey/key.go index bcec5e89404..c6cdd62d3bf 100644 --- a/core/services/keystore/keys/solkey/key.go +++ b/core/services/keystore/keys/solkey/key.go @@ -11,7 +11,7 @@ import ( "github.com/mr-tron/base58" ) -// Raw represents the ETH private key +// Raw represents the Solana private key type Raw []byte // Key gets the Key diff --git a/core/services/keystore/keystoretest.go b/core/services/keystore/keystoretest.go index 91dc87ffe95..e179b51bb54 100644 --- a/core/services/keystore/keystoretest.go +++ b/core/services/keystore/keystoretest.go @@ -73,8 +73,7 @@ func NewInMemory(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr lo p2p: newP2PKeyStore(km), solana: newSolanaKeyStore(km), starknet: newStarkNetKeyStore(km), + aptos: newAptosKeyStore(km), vrf: newVRFKeyStore(km), - dkgSign: newDKGSignKeyStore(km), - dkgEncrypt: newDKGEncryptKeyStore(km), } } diff --git a/core/services/keystore/master.go b/core/services/keystore/master.go index bb5b21a96f0..4076fee6a2a 100644 --- a/core/services/keystore/master.go +++ b/core/services/keystore/master.go @@ -11,10 +11,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -39,8 +38,6 @@ type DefaultEVMChainIDFunc func() (defaultEVMChainID *big.Int, err error) type Master interface { CSA() CSA - DKGSign() DKGSign - DKGEncrypt() DKGEncrypt Eth() Eth OCR() OCR OCR2() OCR2 @@ -48,6 +45,7 @@ type Master interface { Solana() Solana Cosmos() Cosmos StarkNet() StarkNet + Aptos() Aptos VRF() VRF Unlock(ctx context.Context, password string) error IsEmpty(ctx context.Context) (bool, error) @@ -55,17 +53,16 @@ type Master interface { type master struct { *keyManager - cosmos *cosmos - csa *csa - eth *eth - ocr *ocr - ocr2 ocr2 - p2p *p2p - solana *solana - starknet *starknet - vrf *vrf - dkgSign *dkgSign - dkgEncrypt *dkgEncrypt + cosmos *cosmos + csa *csa + eth *eth + ocr *ocr + ocr2 ocr2 + p2p *p2p + solana *solana + starknet *starknet + aptos *aptos + vrf *vrf } func New(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr logger.Logger) Master { @@ -92,20 +89,11 @@ func newMaster(ds sqlutil.DataSource, scryptParams utils.ScryptParams, lggr logg p2p: newP2PKeyStore(km), solana: newSolanaKeyStore(km), starknet: newStarkNetKeyStore(km), + aptos: newAptosKeyStore(km), vrf: newVRFKeyStore(km), - dkgSign: newDKGSignKeyStore(km), - dkgEncrypt: newDKGEncryptKeyStore(km), } } -func (ks *master) DKGEncrypt() DKGEncrypt { - return ks.dkgEncrypt -} - -func (ks master) DKGSign() DKGSign { - return ks.dkgSign -} - func (ks master) CSA() CSA { return ks.csa } @@ -138,6 +126,10 @@ func (ks *master) StarkNet() StarkNet { return ks.starknet } +func (ks *master) Aptos() Aptos { + return ks.aptos +} + func (ks *master) VRF() VRF { return ks.vrf } @@ -273,12 +265,10 @@ func GetFieldNameForKey(unknownKey Key) (string, error) { return "Solana", nil case starkkey.Key: return "StarkNet", nil + case aptoskey.Key: + return "Aptos", nil case vrfkey.KeyV2: return "VRF", nil - case dkgsignkey.Key: - return "DKGSign", nil - case dkgencryptkey.Key: - return "DKGEncrypt", nil } return "", fmt.Errorf("unknown key type: %T", unknownKey) } diff --git a/core/services/keystore/mocks/dkg_sign.go b/core/services/keystore/mocks/aptos.go similarity index 56% rename from core/services/keystore/mocks/dkg_sign.go rename to core/services/keystore/mocks/aptos.go index fd16f573a87..476112149bf 100644 --- a/core/services/keystore/mocks/dkg_sign.go +++ b/core/services/keystore/mocks/aptos.go @@ -1,22 +1,22 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks import ( context "context" - dkgsignkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" + aptoskey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" mock "github.com/stretchr/testify/mock" ) -// DKGSign is an autogenerated mock type for the DKGSign type -type DKGSign struct { +// Aptos is an autogenerated mock type for the Aptos type +type Aptos struct { mock.Mock } // Add provides a mock function with given fields: ctx, key -func (_m *DKGSign) Add(ctx context.Context, key dkgsignkey.Key) error { +func (_m *Aptos) Add(ctx context.Context, key aptoskey.Key) error { ret := _m.Called(ctx, key) if len(ret) == 0 { @@ -24,7 +24,7 @@ func (_m *DKGSign) Add(ctx context.Context, key dkgsignkey.Key) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dkgsignkey.Key) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, aptoskey.Key) error); ok { r0 = rf(ctx, key) } else { r0 = ret.Error(0) @@ -34,22 +34,22 @@ func (_m *DKGSign) Add(ctx context.Context, key dkgsignkey.Key) error { } // Create provides a mock function with given fields: ctx -func (_m *DKGSign) Create(ctx context.Context) (dkgsignkey.Key, error) { +func (_m *Aptos) Create(ctx context.Context) (aptoskey.Key, error) { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Create") } - var r0 dkgsignkey.Key + var r0 aptoskey.Key var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (dkgsignkey.Key, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context) (aptoskey.Key, error)); ok { return rf(ctx) } - if rf, ok := ret.Get(0).(func(context.Context) dkgsignkey.Key); ok { + if rf, ok := ret.Get(0).(func(context.Context) aptoskey.Key); ok { r0 = rf(ctx) } else { - r0 = ret.Get(0).(dkgsignkey.Key) + r0 = ret.Get(0).(aptoskey.Key) } if rf, ok := ret.Get(1).(func(context.Context) error); ok { @@ -62,22 +62,22 @@ func (_m *DKGSign) Create(ctx context.Context) (dkgsignkey.Key, error) { } // Delete provides a mock function with given fields: ctx, id -func (_m *DKGSign) Delete(ctx context.Context, id string) (dkgsignkey.Key, error) { +func (_m *Aptos) Delete(ctx context.Context, id string) (aptoskey.Key, error) { ret := _m.Called(ctx, id) if len(ret) == 0 { panic("no return value specified for Delete") } - var r0 dkgsignkey.Key + var r0 aptoskey.Key var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (dkgsignkey.Key, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, string) (aptoskey.Key, error)); ok { return rf(ctx, id) } - if rf, ok := ret.Get(0).(func(context.Context, string) dkgsignkey.Key); ok { + if rf, ok := ret.Get(0).(func(context.Context, string) aptoskey.Key); ok { r0 = rf(ctx, id) } else { - r0 = ret.Get(0).(dkgsignkey.Key) + r0 = ret.Get(0).(aptoskey.Key) } if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { @@ -90,7 +90,7 @@ func (_m *DKGSign) Delete(ctx context.Context, id string) (dkgsignkey.Key, error } // EnsureKey provides a mock function with given fields: ctx -func (_m *DKGSign) EnsureKey(ctx context.Context) error { +func (_m *Aptos) EnsureKey(ctx context.Context) error { ret := _m.Called(ctx) if len(ret) == 0 { @@ -108,7 +108,7 @@ func (_m *DKGSign) EnsureKey(ctx context.Context) error { } // Export provides a mock function with given fields: id, password -func (_m *DKGSign) Export(id string, password string) ([]byte, error) { +func (_m *Aptos) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) if len(ret) == 0 { @@ -138,22 +138,22 @@ func (_m *DKGSign) Export(id string, password string) ([]byte, error) { } // Get provides a mock function with given fields: id -func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { +func (_m *Aptos) Get(id string) (aptoskey.Key, error) { ret := _m.Called(id) if len(ret) == 0 { panic("no return value specified for Get") } - var r0 dkgsignkey.Key + var r0 aptoskey.Key var r1 error - if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { + if rf, ok := ret.Get(0).(func(string) (aptoskey.Key, error)); ok { return rf(id) } - if rf, ok := ret.Get(0).(func(string) dkgsignkey.Key); ok { + if rf, ok := ret.Get(0).(func(string) aptoskey.Key); ok { r0 = rf(id) } else { - r0 = ret.Get(0).(dkgsignkey.Key) + r0 = ret.Get(0).(aptoskey.Key) } if rf, ok := ret.Get(1).(func(string) error); ok { @@ -166,23 +166,23 @@ func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { } // GetAll provides a mock function with given fields: -func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { +func (_m *Aptos) GetAll() ([]aptoskey.Key, error) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetAll") } - var r0 []dkgsignkey.Key + var r0 []aptoskey.Key var r1 error - if rf, ok := ret.Get(0).(func() ([]dkgsignkey.Key, error)); ok { + if rf, ok := ret.Get(0).(func() ([]aptoskey.Key, error)); ok { return rf() } - if rf, ok := ret.Get(0).(func() []dkgsignkey.Key); ok { + if rf, ok := ret.Get(0).(func() []aptoskey.Key); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]dkgsignkey.Key) + r0 = ret.Get(0).([]aptoskey.Key) } } @@ -196,22 +196,22 @@ func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { } // Import provides a mock function with given fields: ctx, keyJSON, password -func (_m *DKGSign) Import(ctx context.Context, keyJSON []byte, password string) (dkgsignkey.Key, error) { +func (_m *Aptos) Import(ctx context.Context, keyJSON []byte, password string) (aptoskey.Key, error) { ret := _m.Called(ctx, keyJSON, password) if len(ret) == 0 { panic("no return value specified for Import") } - var r0 dkgsignkey.Key + var r0 aptoskey.Key var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (dkgsignkey.Key, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (aptoskey.Key, error)); ok { return rf(ctx, keyJSON, password) } - if rf, ok := ret.Get(0).(func(context.Context, []byte, string) dkgsignkey.Key); ok { + if rf, ok := ret.Get(0).(func(context.Context, []byte, string) aptoskey.Key); ok { r0 = rf(ctx, keyJSON, password) } else { - r0 = ret.Get(0).(dkgsignkey.Key) + r0 = ret.Get(0).(aptoskey.Key) } if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { @@ -223,13 +223,43 @@ func (_m *DKGSign) Import(ctx context.Context, keyJSON []byte, password string) return r0, r1 } -// NewDKGSign creates a new instance of DKGSign. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// Sign provides a mock function with given fields: ctx, id, msg +func (_m *Aptos) Sign(ctx context.Context, id string, msg []byte) ([]byte, error) { + ret := _m.Called(ctx, id, msg) + + if len(ret) == 0 { + panic("no return value specified for Sign") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []byte) ([]byte, error)); ok { + return rf(ctx, id, msg) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []byte) []byte); ok { + r0 = rf(ctx, id, msg) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []byte) error); ok { + r1 = rf(ctx, id, msg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewAptos creates a new instance of Aptos. 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 NewDKGSign(t interface { +func NewAptos(t interface { mock.TestingT Cleanup(func()) -}) *DKGSign { - mock := &DKGSign{} +}) *Aptos { + mock := &Aptos{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/services/keystore/mocks/cosmos.go b/core/services/keystore/mocks/cosmos.go index 5e16a1a3c34..db143e6e345 100644 --- a/core/services/keystore/mocks/cosmos.go +++ b/core/services/keystore/mocks/cosmos.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/csa.go b/core/services/keystore/mocks/csa.go index c99fef9de8c..c3e76f9f690 100644 --- a/core/services/keystore/mocks/csa.go +++ b/core/services/keystore/mocks/csa.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/dkg_encrypt.go b/core/services/keystore/mocks/dkg_encrypt.go deleted file mode 100644 index 48f50b3cec7..00000000000 --- a/core/services/keystore/mocks/dkg_encrypt.go +++ /dev/null @@ -1,238 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - dkgencryptkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - - mock "github.com/stretchr/testify/mock" -) - -// DKGEncrypt is an autogenerated mock type for the DKGEncrypt type -type DKGEncrypt struct { - mock.Mock -} - -// Add provides a mock function with given fields: ctx, key -func (_m *DKGEncrypt) Add(ctx context.Context, key dkgencryptkey.Key) error { - ret := _m.Called(ctx, key) - - if len(ret) == 0 { - panic("no return value specified for Add") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, dkgencryptkey.Key) error); ok { - r0 = rf(ctx, key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Create provides a mock function with given fields: ctx -func (_m *DKGEncrypt) Create(ctx context.Context) (dkgencryptkey.Key, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Create") - } - - var r0 dkgencryptkey.Key - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (dkgencryptkey.Key, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) dkgencryptkey.Key); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(dkgencryptkey.Key) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Delete provides a mock function with given fields: ctx, id -func (_m *DKGEncrypt) Delete(ctx context.Context, id string) (dkgencryptkey.Key, error) { - ret := _m.Called(ctx, id) - - if len(ret) == 0 { - panic("no return value specified for Delete") - } - - var r0 dkgencryptkey.Key - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (dkgencryptkey.Key, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) dkgencryptkey.Key); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(dkgencryptkey.Key) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EnsureKey provides a mock function with given fields: ctx -func (_m *DKGEncrypt) EnsureKey(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for EnsureKey") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Export provides a mock function with given fields: id, password -func (_m *DKGEncrypt) Export(id string, password string) ([]byte, error) { - ret := _m.Called(id, password) - - if len(ret) == 0 { - panic("no return value specified for Export") - } - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { - return rf(id, password) - } - if rf, ok := ret.Get(0).(func(string, string) []byte); ok { - r0 = rf(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) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Get provides a mock function with given fields: id -func (_m *DKGEncrypt) Get(id string) (dkgencryptkey.Key, error) { - ret := _m.Called(id) - - if len(ret) == 0 { - panic("no return value specified for Get") - } - - var r0 dkgencryptkey.Key - var r1 error - if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { - return rf(id) - } - if rf, ok := ret.Get(0).(func(string) dkgencryptkey.Key); ok { - r0 = rf(id) - } else { - r0 = ret.Get(0).(dkgencryptkey.Key) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetAll provides a mock function with given fields: -func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetAll") - } - - var r0 []dkgencryptkey.Key - var r1 error - if rf, ok := ret.Get(0).(func() ([]dkgencryptkey.Key, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []dkgencryptkey.Key); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]dkgencryptkey.Key) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Import provides a mock function with given fields: ctx, keyJSON, password -func (_m *DKGEncrypt) Import(ctx context.Context, keyJSON []byte, password string) (dkgencryptkey.Key, error) { - ret := _m.Called(ctx, keyJSON, password) - - if len(ret) == 0 { - panic("no return value specified for Import") - } - - var r0 dkgencryptkey.Key - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []byte, string) (dkgencryptkey.Key, error)); ok { - return rf(ctx, keyJSON, password) - } - if rf, ok := ret.Get(0).(func(context.Context, []byte, string) dkgencryptkey.Key); ok { - r0 = rf(ctx, keyJSON, password) - } else { - r0 = ret.Get(0).(dkgencryptkey.Key) - } - - if rf, ok := ret.Get(1).(func(context.Context, []byte, string) error); ok { - r1 = rf(ctx, keyJSON, password) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewDKGEncrypt creates a new instance of DKGEncrypt. 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 NewDKGEncrypt(t interface { - mock.TestingT - Cleanup(func()) -}) *DKGEncrypt { - mock := &DKGEncrypt{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index f4a2bea1b02..352605efcd3 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index 2739c4bbe34..d6c089f2a8a 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -14,80 +14,60 @@ type Master struct { mock.Mock } -// CSA provides a mock function with given fields: -func (_m *Master) CSA() keystore.CSA { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for CSA") - } - - var r0 keystore.CSA - if rf, ok := ret.Get(0).(func() keystore.CSA); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(keystore.CSA) - } - } - - return r0 -} - -// Cosmos provides a mock function with given fields: -func (_m *Master) Cosmos() keystore.Cosmos { +// Aptos provides a mock function with given fields: +func (_m *Master) Aptos() keystore.Aptos { ret := _m.Called() if len(ret) == 0 { - panic("no return value specified for Cosmos") + panic("no return value specified for Aptos") } - var r0 keystore.Cosmos - if rf, ok := ret.Get(0).(func() keystore.Cosmos); ok { + var r0 keystore.Aptos + if rf, ok := ret.Get(0).(func() keystore.Aptos); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(keystore.Cosmos) + r0 = ret.Get(0).(keystore.Aptos) } } return r0 } -// DKGEncrypt provides a mock function with given fields: -func (_m *Master) DKGEncrypt() keystore.DKGEncrypt { +// CSA provides a mock function with given fields: +func (_m *Master) CSA() keystore.CSA { ret := _m.Called() if len(ret) == 0 { - panic("no return value specified for DKGEncrypt") + panic("no return value specified for CSA") } - var r0 keystore.DKGEncrypt - if rf, ok := ret.Get(0).(func() keystore.DKGEncrypt); ok { + var r0 keystore.CSA + if rf, ok := ret.Get(0).(func() keystore.CSA); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(keystore.DKGEncrypt) + r0 = ret.Get(0).(keystore.CSA) } } return r0 } -// DKGSign provides a mock function with given fields: -func (_m *Master) DKGSign() keystore.DKGSign { +// Cosmos provides a mock function with given fields: +func (_m *Master) Cosmos() keystore.Cosmos { ret := _m.Called() if len(ret) == 0 { - panic("no return value specified for DKGSign") + panic("no return value specified for Cosmos") } - var r0 keystore.DKGSign - if rf, ok := ret.Get(0).(func() keystore.DKGSign); ok { + var r0 keystore.Cosmos + if rf, ok := ret.Get(0).(func() keystore.Cosmos); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(keystore.DKGSign) + r0 = ret.Get(0).(keystore.Cosmos) } } diff --git a/core/services/keystore/mocks/ocr.go b/core/services/keystore/mocks/ocr.go index 76659d0d4d1..7582295ee15 100644 --- a/core/services/keystore/mocks/ocr.go +++ b/core/services/keystore/mocks/ocr.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/ocr2.go b/core/services/keystore/mocks/ocr2.go index 74c8eed70cc..0771f460db5 100644 --- a/core/services/keystore/mocks/ocr2.go +++ b/core/services/keystore/mocks/ocr2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/p2p.go b/core/services/keystore/mocks/p2p.go index cb5a9329e54..973fc81c950 100644 --- a/core/services/keystore/mocks/p2p.go +++ b/core/services/keystore/mocks/p2p.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/solana.go b/core/services/keystore/mocks/solana.go index 2f9514cc1da..4fde08fc264 100644 --- a/core/services/keystore/mocks/solana.go +++ b/core/services/keystore/mocks/solana.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/starknet.go b/core/services/keystore/mocks/starknet.go index a6cc0d5e5f3..d12a8e9b8fa 100644 --- a/core/services/keystore/mocks/starknet.go +++ b/core/services/keystore/mocks/starknet.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/mocks/vrf.go b/core/services/keystore/mocks/vrf.go index 87c6a724bdb..bc88f045234 100644 --- a/core/services/keystore/mocks/vrf.go +++ b/core/services/keystore/mocks/vrf.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/keystore/models.go b/core/services/keystore/models.go index bb84efdd024..d5eec6802b9 100644 --- a/core/services/keystore/models.go +++ b/core/services/keystore/models.go @@ -11,10 +11,9 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -157,25 +156,23 @@ type keyRing struct { Cosmos map[string]cosmoskey.Key Solana map[string]solkey.Key StarkNet map[string]starkkey.Key + Aptos map[string]aptoskey.Key VRF map[string]vrfkey.KeyV2 - DKGSign map[string]dkgsignkey.Key - DKGEncrypt map[string]dkgencryptkey.Key LegacyKeys LegacyKeyStorage } func newKeyRing() *keyRing { return &keyRing{ - CSA: make(map[string]csakey.KeyV2), - Eth: make(map[string]ethkey.KeyV2), - OCR: make(map[string]ocrkey.KeyV2), - OCR2: make(map[string]ocr2key.KeyBundle), - P2P: make(map[string]p2pkey.KeyV2), - Cosmos: make(map[string]cosmoskey.Key), - Solana: make(map[string]solkey.Key), - StarkNet: make(map[string]starkkey.Key), - VRF: make(map[string]vrfkey.KeyV2), - DKGSign: make(map[string]dkgsignkey.Key), - DKGEncrypt: make(map[string]dkgencryptkey.Key), + CSA: make(map[string]csakey.KeyV2), + Eth: make(map[string]ethkey.KeyV2), + OCR: make(map[string]ocrkey.KeyV2), + OCR2: make(map[string]ocr2key.KeyBundle), + P2P: make(map[string]p2pkey.KeyV2), + Cosmos: make(map[string]cosmoskey.Key), + Solana: make(map[string]solkey.Key), + StarkNet: make(map[string]starkkey.Key), + Aptos: make(map[string]aptoskey.Key), + VRF: make(map[string]vrfkey.KeyV2), } } @@ -233,15 +230,12 @@ func (kr *keyRing) raw() (rawKeys rawKeyRing) { for _, starkkey := range kr.StarkNet { rawKeys.StarkNet = append(rawKeys.StarkNet, starkkey.Raw()) } + for _, aptoskey := range kr.Aptos { + rawKeys.Aptos = append(rawKeys.Aptos, aptoskey.Raw()) + } for _, vrfKey := range kr.VRF { rawKeys.VRF = append(rawKeys.VRF, vrfKey.Raw()) } - for _, dkgSignKey := range kr.DKGSign { - rawKeys.DKGSign = append(rawKeys.DKGSign, dkgSignKey.Raw()) - } - for _, dkgEncryptKey := range kr.DKGEncrypt { - rawKeys.DKGEncrypt = append(rawKeys.DKGEncrypt, dkgEncryptKey.Raw()) - } return rawKeys } @@ -279,18 +273,14 @@ func (kr *keyRing) logPubKeys(lggr logger.Logger) { for _, starkkey := range kr.StarkNet { starknetIDs = append(starknetIDs, starkkey.ID()) } + var aptosIDs []string + for _, aptosKey := range kr.Aptos { + aptosIDs = append(aptosIDs, aptosKey.ID()) + } var vrfIDs []string for _, VRFKey := range kr.VRF { vrfIDs = append(vrfIDs, VRFKey.ID()) } - var dkgSignIDs []string - for _, dkgSignKey := range kr.DKGSign { - dkgSignIDs = append(dkgSignIDs, dkgSignKey.ID()) - } - var dkgEncryptIDs []string - for _, dkgEncryptKey := range kr.DKGEncrypt { - dkgEncryptIDs = append(dkgEncryptIDs, dkgEncryptKey.ID()) - } if len(csaIDs) > 0 { lggr.Infow(fmt.Sprintf("Unlocked %d CSA keys", len(csaIDs)), "keys", csaIDs) } @@ -315,15 +305,12 @@ func (kr *keyRing) logPubKeys(lggr logger.Logger) { if len(starknetIDs) > 0 { lggr.Infow(fmt.Sprintf("Unlocked %d StarkNet keys", len(starknetIDs)), "keys", starknetIDs) } + if len(aptosIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Aptos keys", len(aptosIDs)), "keys", aptosIDs) + } if len(vrfIDs) > 0 { lggr.Infow(fmt.Sprintf("Unlocked %d VRF keys", len(vrfIDs)), "keys", vrfIDs) } - if len(dkgSignIDs) > 0 { - lggr.Infow(fmt.Sprintf("Unlocked %d DKGSign keys", len(dkgSignIDs)), "keys", dkgSignIDs) - } - if len(dkgEncryptIDs) > 0 { - lggr.Infow(fmt.Sprintf("Unlocked %d DKGEncrypt keys", len(dkgEncryptIDs)), "keys", dkgEncryptIDs) - } if len(kr.LegacyKeys.legacyRawKeys) > 0 { lggr.Infow(fmt.Sprintf("%d keys stored in legacy system", kr.LegacyKeys.legacyRawKeys.len())) } @@ -341,9 +328,8 @@ type rawKeyRing struct { Cosmos []cosmoskey.Raw Solana []solkey.Raw StarkNet []starkkey.Raw + Aptos []aptoskey.Raw VRF []vrfkey.Raw - DKGSign []dkgsignkey.Raw - DKGEncrypt []dkgencryptkey.Raw LegacyKeys LegacyKeyStorage `json:"-"` } @@ -382,18 +368,14 @@ func (rawKeys rawKeyRing) keys() (*keyRing, error) { starkKey := rawStarkNetKey.Key() keyRing.StarkNet[starkKey.ID()] = starkKey } + for _, rawAptosKey := range rawKeys.Aptos { + aptosKey := rawAptosKey.Key() + keyRing.Aptos[aptosKey.ID()] = aptosKey + } for _, rawVRFKey := range rawKeys.VRF { vrfKey := rawVRFKey.Key() keyRing.VRF[vrfKey.ID()] = vrfKey } - for _, rawDKGSignKey := range rawKeys.DKGSign { - dkgSignKey := rawDKGSignKey.Key() - keyRing.DKGSign[dkgSignKey.ID()] = dkgSignKey - } - for _, rawDKGEncryptKey := range rawKeys.DKGEncrypt { - dkgEncryptKey := rawDKGEncryptKey.Key() - keyRing.DKGEncrypt[dkgEncryptKey.ID()] = dkgEncryptKey - } keyRing.LegacyKeys = rawKeys.LegacyKeys return keyRing, nil diff --git a/core/services/keystore/models_test.go b/core/services/keystore/models_test.go index 25331a3b218..8f7881809ea 100644 --- a/core/services/keystore/models_test.go +++ b/core/services/keystore/models_test.go @@ -11,8 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -42,19 +40,15 @@ func TestKeyRing_Encrypt_Decrypt(t *testing.T) { sol1, sol2 := solkey.MustNewInsecure(rand.Reader), solkey.MustNewInsecure(rand.Reader) vrf1, vrf2 := vrfkey.MustNewV2XXXTestingOnly(big.NewInt(1)), vrfkey.MustNewV2XXXTestingOnly(big.NewInt(2)) tk1, tk2 := cosmoskey.MustNewInsecure(rand.Reader), cosmoskey.MustNewInsecure(rand.Reader) - dkgsign1, dkgsign2 := dkgsignkey.MustNewXXXTestingOnly(big.NewInt(1)), dkgsignkey.MustNewXXXTestingOnly(big.NewInt(2)) - dkgencrypt1, dkgencrypt2 := dkgencryptkey.MustNewXXXTestingOnly(big.NewInt(1)), dkgencryptkey.MustNewXXXTestingOnly(big.NewInt(2)) originalKeyRingRaw := rawKeyRing{ - CSA: []csakey.Raw{csa1.Raw(), csa2.Raw()}, - Eth: []ethkey.Raw{eth1.Raw(), eth2.Raw()}, - OCR: []ocrkey.Raw{ocr[0].Raw(), ocr[1].Raw()}, - OCR2: ocr2_raw, - P2P: []p2pkey.Raw{p2p1.Raw(), p2p2.Raw()}, - Solana: []solkey.Raw{sol1.Raw(), sol2.Raw()}, - VRF: []vrfkey.Raw{vrf1.Raw(), vrf2.Raw()}, - Cosmos: []cosmoskey.Raw{tk1.Raw(), tk2.Raw()}, - DKGSign: []dkgsignkey.Raw{dkgsign1.Raw(), dkgsign2.Raw()}, - DKGEncrypt: []dkgencryptkey.Raw{dkgencrypt1.Raw(), dkgencrypt2.Raw()}, + CSA: []csakey.Raw{csa1.Raw(), csa2.Raw()}, + Eth: []ethkey.Raw{eth1.Raw(), eth2.Raw()}, + OCR: []ocrkey.Raw{ocr[0].Raw(), ocr[1].Raw()}, + OCR2: ocr2_raw, + P2P: []p2pkey.Raw{p2p1.Raw(), p2p2.Raw()}, + Solana: []solkey.Raw{sol1.Raw(), sol2.Raw()}, + VRF: []vrfkey.Raw{vrf1.Raw(), vrf2.Raw()}, + Cosmos: []cosmoskey.Raw{tk1.Raw(), tk2.Raw()}, } originalKeyRing, kerr := originalKeyRingRaw.keys() require.NoError(t, kerr) @@ -109,14 +103,6 @@ func TestKeyRing_Encrypt_Decrypt(t *testing.T) { require.Equal(t, 2, len(decryptedKeyRing.VRF)) require.Equal(t, originalKeyRing.VRF[vrf1.ID()].PublicKey, decryptedKeyRing.VRF[vrf1.ID()].PublicKey) require.Equal(t, originalKeyRing.VRF[vrf2.ID()].PublicKey, decryptedKeyRing.VRF[vrf2.ID()].PublicKey) - // compare dkgsign keys - require.Equal(t, 2, len(decryptedKeyRing.DKGSign)) - require.Equal(t, originalKeyRing.DKGSign[dkgsign1.ID()].PublicKey, decryptedKeyRing.DKGSign[dkgsign1.ID()].PublicKey) - require.Equal(t, originalKeyRing.DKGSign[dkgsign2.ID()].PublicKey, decryptedKeyRing.DKGSign[dkgsign2.ID()].PublicKey) - // compare dkgencrypt keys - require.Equal(t, 2, len(decryptedKeyRing.DKGEncrypt)) - require.Equal(t, originalKeyRing.DKGEncrypt[dkgencrypt1.ID()].PublicKey, decryptedKeyRing.DKGEncrypt[dkgencrypt1.ID()].PublicKey) - require.Equal(t, originalKeyRing.DKGEncrypt[dkgencrypt2.ID()].PublicKey, decryptedKeyRing.DKGEncrypt[dkgencrypt2.ID()].PublicKey) }) t.Run("test legacy system", func(t *testing.T) { diff --git a/core/services/keystore/solana.go b/core/services/keystore/solana.go index e95af37a7fa..ba4031b64cc 100644 --- a/core/services/keystore/solana.go +++ b/core/services/keystore/solana.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" ) @@ -28,6 +29,8 @@ type SolanaSigner struct { Solana } +var _ loop.Keystore = &SolanaSigner{} + func (s *SolanaSigner) Accounts(ctx context.Context) (accounts []string, err error) { ks, err := s.GetAll() if err != nil { diff --git a/core/services/llo/onchain_channel_definition_cache.go b/core/services/llo/onchain_channel_definition_cache.go index d72079d0b1e..5c89561481a 100644 --- a/core/services/llo/onchain_channel_definition_cache.go +++ b/core/services/llo/onchain_channel_definition_cache.go @@ -19,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/channel_config_store" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ChannelDefinitionCacheORM interface { @@ -114,7 +113,8 @@ const pollInterval = 1 * time.Second func (c *channelDefinitionCache) poll() { defer c.wg.Done() - pollT := time.NewTicker(utils.WithJitter(pollInterval)) + pollT := services.NewTicker(pollInterval) + defer pollT.Stop() for { select { diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index 09be8c23453..71b5f301a50 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr/mocks/ocr_contract_tracker_db.go b/core/services/ocr/mocks/ocr_contract_tracker_db.go index d3dcce2641b..8abfbba7f69 100644 --- a/core/services/ocr/mocks/ocr_contract_tracker_db.go +++ b/core/services/ocr/mocks/ocr_contract_tracker_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 875ee0f69ed..9066afd740b 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -36,10 +36,6 @@ import ( llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" @@ -50,8 +46,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/llo" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic" lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" @@ -61,12 +55,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21" ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" - ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" - ocr2coordinator "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/reportserializer" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/promwrapper" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -121,8 +109,6 @@ type Delegate struct { cfg DelegateConfig lggr logger.Logger ks keystore.OCR2 - dkgSignKs keystore.DKGSign - dkgEncryptKs keystore.DKGEncrypt ethKs keystore.Eth RelayGetter isNewlyCreatedJob bool // Set to true if this is a new job freshly added, false if job was present already on node boot. @@ -231,8 +217,6 @@ func NewDelegate( lggr logger.Logger, cfg DelegateConfig, ks keystore.OCR2, - dkgSignKs keystore.DKGSign, - dkgEncryptKs keystore.DKGEncrypt, ethKs keystore.Eth, relayers RelayGetter, mailMon *mailbox.Monitor, @@ -251,8 +235,6 @@ func NewDelegate( cfg: cfg, lggr: lggr.Named("OCR2"), ks: ks, - dkgSignKs: dkgSignKs, - dkgEncryptKs: dkgEncryptKs, ethKs: ethKs, RelayGetter: relayers, isNewlyCreatedJob: false, @@ -310,11 +292,6 @@ func (d *Delegate) cleanupEVM(ctx context.Context, jb job.Job, relayID types.Rel var filters []string switch spec.PluginType { - case types.OCR2VRF: - filters, err = ocr2coordinator.FilterNamesFromSpec(spec) - if err != nil { - d.lggr.Errorw("failed to derive ocr2vrf filter names from spec", "err", err, "spec", spec) - } case types.OCR2Keeper: // Not worth the effort to validate and parse the job spec config to figure out whether this is v2.0 or v2.1, // simpler and faster to just Unregister them both @@ -453,12 +430,6 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi case types.Median: return d.newServicesMedian(ctx, lggr, jb, bootstrapPeers, kb, kvStore, ocrDB, lc) - case types.DKG: - return d.newServicesDKG(lggr, jb, bootstrapPeers, kb, ocrDB, lc) - - case types.OCR2VRF: - return d.newServicesOCR2VRF(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc) - case types.OCR2Keeper: return d.newServicesOCR2Keepers(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc) @@ -494,8 +465,8 @@ func GetEVMEffectiveTransmitterID(ctx context.Context, jb *job.Job, chain legacy if err != nil { return "", err } - if len(sendingKeys) > 1 && spec.PluginType != types.OCR2VRF { - return "", errors.New("only ocr2 vrf should have more than 1 sending key") + if len(sendingKeys) > 1 { + return "", errors.New("no plugin should have more than 1 sending key") } spec.TransmitterID = null.StringFrom(sendingKeys[0]) } @@ -1062,245 +1033,6 @@ func (d *Delegate) newServicesMedian( return medianServices, err2 } -func (d *Delegate) newServicesDKG( - lggr logger.SugaredLogger, - jb job.Job, - bootstrapPeers []commontypes.BootstrapperLocator, - kb ocr2key.KeyBundle, - ocrDB *db, - lc ocrtypes.LocalConfig, -) ([]job.ServiceCtx, error) { - spec := jb.OCR2OracleSpec - rid, err := spec.RelayID() - if err != nil { - return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "DKG"} - } - if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("DKG services: expected EVM relayer got %q", rid.Network) - } - - chain, err2 := d.legacyChains.Get(rid.ChainID) - if err2 != nil { - return nil, fmt.Errorf("DKG services: failed to get chain %s: %w", rid.ChainID, err2) - } - ocr2vrfRelayer := evmrelay.NewOCR2VRFRelayer(chain, lggr.Named("OCR2VRFRelayer"), d.ethKs) - dkgProvider, err2 := ocr2vrfRelayer.NewDKGProvider( - types.RelayArgs{ - ExternalJobID: jb.ExternalJobID, - JobID: jb.ID, - ContractID: spec.ContractID, - New: d.isNewlyCreatedJob, - RelayConfig: spec.RelayConfig.Bytes(), - }, types.PluginArgs{ - TransmitterID: spec.TransmitterID.String, - PluginConfig: spec.PluginConfig.Bytes(), - }) - if err2 != nil { - return nil, err2 - } - ocrLogger := ocrcommon.NewOCRWrapper(lggr, d.cfg.OCR2().TraceLogging(), func(ctx context.Context, msg string) { - lggr.ErrorIf(d.jobORM.RecordError(ctx, jb.ID, msg), "unable to record error") - }) - noopMonitoringEndpoint := telemetry.NoopAgent{} - oracleArgsNoPlugin := libocr2.OCR2OracleArgs{ - BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, - V2Bootstrappers: bootstrapPeers, - ContractTransmitter: dkgProvider.ContractTransmitter(), - ContractConfigTracker: dkgProvider.ContractConfigTracker(), - Database: ocrDB, - LocalConfig: lc, - Logger: ocrLogger, - // Telemetry ingress for DKG is currently not supported so a noop monitoring endpoint is being used - MonitoringEndpoint: &noopMonitoringEndpoint, - OffchainConfigDigester: dkgProvider.OffchainConfigDigester(), - OffchainKeyring: kb, - OnchainKeyring: kb, - MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"job_name": jb.Name.ValueOrZero()}, prometheus.DefaultRegisterer), - } - services, err := dkg.NewDKGServices(jb, dkgProvider, lggr, ocrLogger, d.dkgSignKs, d.dkgEncryptKs, chain.Client(), oracleArgsNoPlugin, d.ds, chain.ID(), spec.Relay) - if err != nil { - return nil, err - } - services = append(services, ocrLogger) - return services, nil -} - -func (d *Delegate) newServicesOCR2VRF( - ctx context.Context, - lggr logger.SugaredLogger, - jb job.Job, - bootstrapPeers []commontypes.BootstrapperLocator, - kb ocr2key.KeyBundle, - ocrDB *db, - lc ocrtypes.LocalConfig, -) ([]job.ServiceCtx, error) { - spec := jb.OCR2OracleSpec - - rid, err := spec.RelayID() - if err != nil { - return nil, ErrJobSpecNoRelayer{Err: err, PluginName: "VRF"} - } - if rid.Network != relay.NetworkEVM { - return nil, fmt.Errorf("VRF services: expected EVM relayer got %q", rid.Network) - } - chain, err2 := d.legacyChains.Get(rid.ChainID) - if err2 != nil { - return nil, fmt.Errorf("VRF services: failed to get chain (%s): %w", rid.ChainID, err2) - } - if jb.ForwardingAllowed != chain.Config().EVM().Transactions().ForwardersEnabled() { - return nil, errors.New("transaction forwarding settings must be consistent for ocr2vrf") - } - - var cfg ocr2vrfconfig.PluginConfig - err2 = json.Unmarshal(spec.PluginConfig.Bytes(), &cfg) - if err2 != nil { - return nil, errors.Wrap(err2, "unmarshal ocr2vrf plugin config") - } - - err2 = ocr2vrfconfig.ValidatePluginConfig(cfg, d.dkgSignKs, d.dkgEncryptKs) - if err2 != nil { - return nil, errors.Wrap(err2, "validate ocr2vrf plugin config") - } - - ocr2vrfRelayer := evmrelay.NewOCR2VRFRelayer(chain, lggr.Named("OCR2VRFRelayer"), d.ethKs) - transmitterID := spec.TransmitterID.String - - vrfProvider, err2 := ocr2vrfRelayer.NewOCR2VRFProvider( - types.RelayArgs{ - ExternalJobID: jb.ExternalJobID, - JobID: jb.ID, - ContractID: spec.ContractID, - New: d.isNewlyCreatedJob, - RelayConfig: spec.RelayConfig.Bytes(), - }, types.PluginArgs{ - TransmitterID: transmitterID, - PluginConfig: spec.PluginConfig.Bytes(), - }) - if err2 != nil { - return nil, errors.Wrap(err2, "new vrf provider") - } - - dkgProvider, err2 := ocr2vrfRelayer.NewDKGProvider( - types.RelayArgs{ - ExternalJobID: jb.ExternalJobID, - JobID: jb.ID, - ContractID: cfg.DKGContractAddress, - RelayConfig: spec.RelayConfig.Bytes(), - }, types.PluginArgs{ - TransmitterID: transmitterID, - PluginConfig: spec.PluginConfig.Bytes(), - }) - if err2 != nil { - return nil, errors.Wrap(err2, "new dkg provider") - } - - dkgContract, err2 := dkg.NewOnchainDKGClient(cfg.DKGContractAddress, chain.Client()) - if err2 != nil { - return nil, errors.Wrap(err2, "new onchain dkg client") - } - - timeout := 5 * time.Second - interval := 60 * time.Second - juelsLogger := lggr.Named("JuelsFeeCoin").With("contract", cfg.LinkEthFeedAddress, "timeout", timeout, "interval", interval) - juelsPerFeeCoin, err2 := juelsfeecoin.NewLinkEthPriceProvider( - common.HexToAddress(cfg.LinkEthFeedAddress), chain.Client(), timeout, interval, juelsLogger) - if err2 != nil { - return nil, errors.Wrap(err2, "new link eth price provider") - } - - reasonableGasPrice := reasonablegasprice.NewReasonableGasPriceProvider( - chain.GasEstimator(), - timeout, - chain.Config().EVM().GasEstimator().PriceMax(), - chain.Config().EVM().GasEstimator().EIP1559DynamicFees(), - ) - - encryptionSecretKey, err2 := d.dkgEncryptKs.Get(cfg.DKGEncryptionPublicKey) - if err2 != nil { - return nil, errors.Wrap(err2, "get DKG encryption key") - } - signingSecretKey, err2 := d.dkgSignKs.Get(cfg.DKGSigningPublicKey) - if err2 != nil { - return nil, errors.Wrap(err2, "get DKG signing key") - } - keyID, err2 := dkg.DecodeKeyID(cfg.DKGKeyID) - if err2 != nil { - return nil, errors.Wrap(err2, "decode DKG key ID") - } - - coordinator, err2 := ocr2coordinator.New( - ctx, - lggr.Named("OCR2VRFCoordinator"), - common.HexToAddress(spec.ContractID), - common.HexToAddress(cfg.VRFCoordinatorAddress), - common.HexToAddress(cfg.DKGContractAddress), - chain.Client(), - chain.LogPoller(), - chain.Config().EVM().FinalityDepth(), - ) - if err2 != nil { - return nil, errors.Wrap(err2, "create ocr2vrf coordinator") - } - l := lggr.Named("OCR2VRF").With( - "jobName", jb.Name.ValueOrZero(), - "jobID", jb.ID, - ) - vrfLogger := ocrcommon.NewOCRWrapper(l.With("vrfContractID", spec.ContractID), d.cfg.OCR2().TraceLogging(), func(ctx context.Context, msg string) { - lggr.ErrorIf(d.jobORM.RecordError(ctx, jb.ID, msg), "unable to record error") - }) - dkgLogger := ocrcommon.NewOCRWrapper(l.With("dkgContractID", cfg.DKGContractAddress), d.cfg.OCR2().TraceLogging(), func(ctx context.Context, msg string) { - lggr.ErrorIf(d.jobORM.RecordError(ctx, jb.ID, msg), "unable to record error") - }) - dkgReportingPluginFactoryDecorator := func(wrapped ocrtypes.ReportingPluginFactory) ocrtypes.ReportingPluginFactory { - return promwrapper.NewPromFactory(wrapped, "DKG", string(relay.NetworkEVM), chain.ID()) - } - vrfReportingPluginFactoryDecorator := func(wrapped ocrtypes.ReportingPluginFactory) ocrtypes.ReportingPluginFactory { - return promwrapper.NewPromFactory(wrapped, "OCR2VRF", string(relay.NetworkEVM), chain.ID()) - } - noopMonitoringEndpoint := telemetry.NoopAgent{} - oracles, err2 := ocr2vrf.NewOCR2VRF(ocr2vrf.DKGVRFArgs{ - VRFLogger: vrfLogger, - DKGLogger: dkgLogger, - BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, - V2Bootstrappers: bootstrapPeers, - OffchainKeyring: kb, - OnchainKeyring: kb, - VRFOffchainConfigDigester: vrfProvider.OffchainConfigDigester(), - VRFContractConfigTracker: vrfProvider.ContractConfigTracker(), - VRFContractTransmitter: vrfProvider.ContractTransmitter(), - VRFDatabase: ocrDB, - VRFLocalConfig: lc, - VRFMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.OCR2VRF), - DKGContractConfigTracker: dkgProvider.ContractConfigTracker(), - DKGOffchainConfigDigester: dkgProvider.OffchainConfigDigester(), - DKGContract: dkgpkg.NewOnchainContract(dkgContract, &altbn_128.G2{}), - DKGContractTransmitter: dkgProvider.ContractTransmitter(), - DKGDatabase: ocrDB, - DKGLocalConfig: lc, - // Telemetry ingress for DKG is currently not supported so a noop monitoring endpoint is being used - DKGMonitoringEndpoint: &noopMonitoringEndpoint, - Serializer: reportserializer.NewReportSerializer(&altbn_128.G1{}), - JuelsPerFeeCoin: juelsPerFeeCoin, - ReasonableGasPrice: reasonableGasPrice, - Coordinator: coordinator, - Esk: encryptionSecretKey.KyberScalar(), - Ssk: signingSecretKey.KyberScalar(), - KeyID: keyID, - DKGReportingPluginFactoryDecorator: dkgReportingPluginFactoryDecorator, - VRFReportingPluginFactoryDecorator: vrfReportingPluginFactoryDecorator, - DKGSharePersistence: persistence.NewShareDB(d.ds, lggr.Named("DKGShareDB"), chain.ID(), spec.Relay), - }) - if err2 != nil { - return nil, errors.Wrap(err2, "new ocr2vrf") - } - - // NOTE: we return from here with the services because the OCR2VRF oracles are defined - // and exported from the ocr2vrf library. It takes care of running the DKG and OCR2VRF - // oracles under the hood together. - oracleCtx := job.NewServiceAdapter(oracles) - return []job.ServiceCtx{vrfProvider, dkgProvider, oracleCtx}, nil -} - func (d *Delegate) newServicesOCR2Keepers( ctx context.Context, lggr logger.SugaredLogger, diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index 1e4be66c7d1..9015928ade1 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -99,12 +99,6 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002", "0x7e57000000000000000000000000000000000003"}, expectedError: true, }, - { - name: "when transmitterID is not defined and plugin is ocr2vrf, it should allow>1 sendingKeys and set transmitterID to the first one", - pluginType: types.OCR2VRF, - sendingKeys: []any{"0x7e57000000000000000000000000000000000000", "0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, - expectedTransmitterID: "0x7e57000000000000000000000000000000000000", - }, { name: "when transmitterID is not defined, it should set transmitterID to first sendingKey", sendingKeys: []any{"0x7e57000000000000000000000000000000000004"}, @@ -117,23 +111,6 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), expectedTransmitterID: "0x7e58000000000000000000000000000000000000", }, - { - name: "when forwarders are enabled and when transmitterID is not defined, it should use first sendingKey to retrieve forwarder address", - pluginType: types.OCR2VRF, - forwardingEnabled: true, - sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, - getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), - expectedTransmitterID: "0x7e58000000000000000000000000000000000000", - }, - { - name: "when forwarders are enabled but forwarder address fails to be retrieved and when transmitterID is not defined, it should default to using first sendingKey", - pluginType: types.OCR2VRF, - forwardingEnabled: true, - sendingKeys: []any{"0x7e57000000000000000000000000000000000001", "0x7e57000000000000000000000000000000000002"}, - getForwarderForEOAArg: common.HexToAddress("0x7e57000000000000000000000000000000000001"), - getForwarderForEOAErr: true, - expectedTransmitterID: "0x7e57000000000000000000000000000000000001", - }, { name: "when forwarders are enabled but forwarder address fails to be retrieved and when transmitterID is defined, it should default to using spec transmitterID", forwardingEnabled: true, diff --git a/core/services/ocr2/plugins/dkg/config/config.go b/core/services/ocr2/plugins/dkg/config/config.go deleted file mode 100644 index b848b9b3e2e..00000000000 --- a/core/services/ocr2/plugins/dkg/config/config.go +++ /dev/null @@ -1,28 +0,0 @@ -package config - -import ( - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" -) - -// PluginConfig contains custom arguments for the DKG plugin. -type PluginConfig struct { - EncryptionPublicKey string `json:"encryptionPublicKey"` - SigningPublicKey string `json:"signingPublicKey"` - KeyID string `json:"keyID"` -} - -// ValidatePluginConfig validates that the given DKG plugin configuration is correct. -func ValidatePluginConfig(config PluginConfig, dkgSignKs keystore.DKGSign, dkgEncryptKs keystore.DKGEncrypt) error { - _, err := dkgEncryptKs.Get(config.EncryptionPublicKey) - if err != nil { - return errors.Wrapf(err, "DKG encryption key: %s not found in key store", config.EncryptionPublicKey) - } - _, err = dkgSignKs.Get(config.SigningPublicKey) - if err != nil { - return errors.Wrapf(err, "DKG sign key: %s not found in key store", config.SigningPublicKey) - } - - return nil -} diff --git a/core/services/ocr2/plugins/dkg/config/config_test.go b/core/services/ocr2/plugins/dkg/config/config_test.go deleted file mode 100644 index f8cc1265ee1..00000000000 --- a/core/services/ocr2/plugins/dkg/config/config_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package config_test - -import ( - "encoding/hex" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" -) - -func TestValidatePluginConfig(t *testing.T) { - t.Parallel() - ctx := testutils.Context(t) - - db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db) - - dkgEncryptKey, err := kst.DKGEncrypt().Create(ctx) - require.NoError(t, err) - dkgSignKey, err := kst.DKGSign().Create(ctx) - require.NoError(t, err) - - encryptKeyBytes, err := dkgEncryptKey.PublicKey.MarshalBinary() - require.NoError(t, err) - encryptKey := hex.EncodeToString(encryptKeyBytes) - - signKeyBytes, err := dkgSignKey.PublicKey.MarshalBinary() - require.NoError(t, err) - signKey := hex.EncodeToString(signKeyBytes) - - pluginConfig := config.PluginConfig{ - EncryptionPublicKey: encryptKey, - SigningPublicKey: signKey, - } - t.Run("no error when keys are found", func(t *testing.T) { - err = config.ValidatePluginConfig(pluginConfig, kst.DKGSign(), kst.DKGEncrypt()) - require.NoError(t, err) - }) - - t.Run("error when encryption key not found", func(t *testing.T) { - pluginConfig = config.PluginConfig{ - EncryptionPublicKey: "wrongKey", - SigningPublicKey: signKey, - } - err = config.ValidatePluginConfig(pluginConfig, kst.DKGSign(), kst.DKGEncrypt()) - require.Error(t, err) - require.Contains(t, err.Error(), "DKG encryption key: wrongKey not found in key store") - }) - - t.Run("error when sign key not found", func(t *testing.T) { - pluginConfig = config.PluginConfig{ - EncryptionPublicKey: encryptKey, - SigningPublicKey: "wrongKey", - } - - err = config.ValidatePluginConfig(pluginConfig, kst.DKGSign(), kst.DKGEncrypt()) - require.Error(t, err) - require.Contains(t, err.Error(), "DKG sign key: wrongKey not found in key store") - }) -} diff --git a/core/services/ocr2/plugins/dkg/key_consumer.go b/core/services/ocr2/plugins/dkg/key_consumer.go deleted file mode 100644 index 23ca7e795bf..00000000000 --- a/core/services/ocr2/plugins/dkg/key_consumer.go +++ /dev/null @@ -1,24 +0,0 @@ -package dkg - -import ( - "encoding/hex" - "fmt" - - "github.com/smartcontractkit/chainlink-vrf/dkg" -) - -type dummyKeyConsumer struct{} - -func (d dummyKeyConsumer) KeyInvalidated(keyID dkg.KeyID) { - fmt.Println("KEY INVALIDATED:", hex.EncodeToString(keyID[:])) -} - -func (d dummyKeyConsumer) NewKey(keyID dkg.KeyID, data *dkg.KeyData) { - fmt.Println("NEW KEY FOR KEY ID:", hex.EncodeToString(keyID[:]), "KEY:", data) -} - -var _ dkg.KeyConsumer = dummyKeyConsumer{} - -func newDummyKeyConsumer() dummyKeyConsumer { - return dummyKeyConsumer{} -} diff --git a/core/services/ocr2/plugins/dkg/onchain_contract.go b/core/services/ocr2/plugins/dkg/onchain_contract.go deleted file mode 100644 index c6ea84de235..00000000000 --- a/core/services/ocr2/plugins/dkg/onchain_contract.go +++ /dev/null @@ -1,90 +0,0 @@ -package dkg - -import ( - "context" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - "go.dedis.ch/kyber/v3/sign/anon" - - "github.com/smartcontractkit/chainlink-vrf/dkg" - dkgwrapper "github.com/smartcontractkit/chainlink-vrf/gethwrappers/dkg" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" -) - -type onchainContract struct { - wrapper *dkgwrapper.DKG - dkgAddress common.Address -} - -var _ dkg.DKG = &onchainContract{} - -func NewOnchainDKGClient(dkgAddress string, ethClient evmclient.Client) (dkg.DKG, error) { - dkgAddr := common.HexToAddress(dkgAddress) - wrapper, err := dkgwrapper.NewDKG(dkgAddr, ethClient) - if err != nil { - return nil, errors.Wrap(err, "new dkg wrapper") - } - return &onchainContract{ - wrapper: wrapper, - dkgAddress: dkgAddr, - }, nil -} - -func (o *onchainContract) GetKey( - ctx context.Context, - keyID dkg.KeyID, - configDigest [32]byte, -) (dkg.OnchainKeyData, error) { - keyData, err := o.wrapper.GetKey(&bind.CallOpts{ - Context: ctx, - }, keyID, configDigest) - if err != nil { - return dkg.OnchainKeyData{}, errors.Wrap(err, "wrapper GetKey") - } - return dkg.OnchainKeyData{ - PublicKey: keyData.PublicKey, - Hashes: keyData.Hashes, - }, nil -} - -func (o *onchainContract) Address() common.Address { - return o.dkgAddress -} - -func (o *onchainContract) CurrentCommittee(ctx context.Context) (ocr2vrftypes.OCRCommittee, error) { - // NOTE: this is only ever used in tests in the ocr2vrf repo. - // Since this isn't really used for production DKG running, - // there's no point in implementing it. - panic("unimplemented") -} - -func (o *onchainContract) InitiateDKG( - ctx context.Context, - committee ocr2vrftypes.OCRCommittee, - f ocr2vrftypes.PlayerIdxInt, - keyID dkg.KeyID, - epks dkg.EncryptionPublicKeys, - spks dkg.SigningPublicKeys, - encGroup anon.Suite, - translator ocr2vrftypes.PubKeyTranslation, -) error { - // NOTE: this is only ever used in tests, the idea here is to call setConfig - // on the DKG contract to get the OCR process going. Since this isn't really - // used for production DKG running, there's no point in implementing it. - panic("unimplemented") -} - -func (o *onchainContract) AddClient( - ctx context.Context, - keyID [32]byte, - clientAddress common.Address, -) error { - // NOTE: this is only ever used in tests in the ocr2vrf repo. - // Since this isn't really used for production DKG running, - // there's no point in implementing it. - panic("unimplemented") -} diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go deleted file mode 100644 index 07dad494ed7..00000000000 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ /dev/null @@ -1,224 +0,0 @@ -package persistence - -import ( - "bytes" - "context" - "database/sql" - "fmt" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/jmoiron/sqlx" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - "github.com/smartcontractkit/chainlink-vrf/types/hash" - - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -var ( - _ ocr2vrftypes.DKGSharePersistence = &shareDB{} - zeroHash hash.Hash - buckets = []float64{ - float64(100 * time.Millisecond), - float64(200 * time.Millisecond), - float64(500 * time.Millisecond), - float64(1 * time.Second), - float64(2 * time.Second), - float64(5 * time.Second), - float64(10 * time.Second), - float64(30 * time.Second), - } - labels = []string{ - "chainType", "chainID", - } - promWriteShareRecords = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "write_share_records_time", - Help: "The duration of the DKG WriteShareRecords call", - Buckets: buckets, - }, labels) - promReadShareRecords = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "read_share_records_time", - Help: "The duration of the DKG ReadShareRecords call.", - Buckets: buckets, - }, labels) -) - -type shareDB struct { - ds sqlutil.DataSource - lggr logger.Logger - chainID *big.Int - chainType string -} - -// NewShareDB creates a new DKG share database. -func NewShareDB(ds sqlutil.DataSource, lggr logger.Logger, chainID *big.Int, chainType string) ocr2vrftypes.DKGSharePersistence { - return &shareDB{ - ds: ds, - lggr: lggr, - chainID: chainID, - chainType: chainType, - } -} - -// WriteShareRecords writes the provided (already encrypted) -// share records to the Chainlink database. -func (s *shareDB) WriteShareRecords( - ctx context.Context, - cfgDgst ocrtypes.ConfigDigest, - keyID [32]byte, - shareRecords []ocr2vrftypes.PersistentShareSetRecord, -) error { - lggr := s.lggr.With( - "configDigest", hexutil.Encode(cfgDgst[:]), - "keyID", hexutil.Encode(keyID[:])) - - start := time.Now() - defer func() { - duration := time.Since(start) - promWriteShareRecords.WithLabelValues(s.chainType, s.chainID.String()).Observe(float64(duration)) - // lggr.Debugw("Inserted DKG shares into DB", "duration", duration) // see ocr2vrf code for logs - }() - - var named []dkgShare - for _, record := range shareRecords { - if bytes.Equal(record.Hash[:], zeroHash[:]) { - // see ocr2vrf for logging - // lggr.Warnw("skipping record with zero hash", - // "player", record.Dealer.String(), - // "hash", hexutil.Encode(record.Hash[:]), - // ) - continue - } - - // XXX: this might be expensive, but is a good sanity check. - localHash := hash.GetHash(record.MarshaledShareRecord) - if !bytes.Equal(record.Hash[:], localHash[:]) { - return fmt.Errorf("local hash doesn't match given hash in record, expected: %x, got: %x", - localHash[:], record.Hash[:]) - } - - var h hash.Hash - if copied := copy(h[:], record.Hash[:]); copied != 32 { - return fmt.Errorf("wrong number of bytes copied in hash (dealer:%s) %x: %d", - record.Dealer.String(), record.Hash[:], copied) - } - - named = append(named, dkgShare{ - ConfigDigest: cfgDgst[:], - KeyID: keyID[:], - Dealer: record.Dealer.Marshal(), - MarshaledShareRecord: record.MarshaledShareRecord, - /* TODO/WTF: can't do "record.Hash[:]": this leads to store the last record's hash for all the records! */ - RecordHash: h[:], - }) - } - - if len(named) == 0 { - lggr.Infow("No valid share records to insert") - return nil - } - - // see ocr2vrf for logging - // lggr.Infow("Inserting DKG shares into DB", - // "shareHashes", shareHashes(shareRecords), - // "numRecords", len(shareRecords), - // "numNamed", len(named)) - - // Always upsert because we want the number of rows in the table to match - // the number of members of the committee. - _, err := s.ds.NamedExecContext(ctx, ` -INSERT INTO dkg_shares (config_digest, key_id, dealer, marshaled_share_record, record_hash) -VALUES (:config_digest, :key_id, :dealer, :marshaled_share_record, :record_hash) -ON CONFLICT ON CONSTRAINT dkg_shares_pkey -DO UPDATE SET marshaled_share_record = EXCLUDED.marshaled_share_record, record_hash = EXCLUDED.record_hash -`, named[:]) - return err -} - -// ReadShareRecords retrieves any share records in the database that correspond -// to the provided config digest and DKG key ID. -func (s *shareDB) ReadShareRecords( - cfgDgst ocrtypes.ConfigDigest, - keyID [32]byte, -) ( - retrievedShares []ocr2vrftypes.PersistentShareSetRecord, - err error, -) { - ctx := context.Background() //TODO https://smartcontract-it.atlassian.net/browse/BCF-2887 - lggr := s.lggr.With( - "configDigest", hexutil.Encode(cfgDgst[:]), - "keyID", hexutil.Encode(keyID[:])) - - start := time.Now() - defer func() { - duration := time.Since(start) - promReadShareRecords.WithLabelValues(s.chainType, s.chainID.String()).Observe(float64(duration)) - lggr.Debugw("Finished reading DKG shares from DB", "duration", duration) - }() - - a := map[string]any{ - "config_digest": cfgDgst[:], - "key_id": keyID[:], - } - query, args, err := sqlx.Named( - ` -SELECT * -FROM dkg_shares -WHERE config_digest = :config_digest - AND key_id = :key_id -`, a) - if err != nil { - return nil, errors.Wrap(err, "sqlx Named") - } - query = s.ds.Rebind(query) - var dkgShares []dkgShare - err = s.ds.SelectContext(ctx, &dkgShares, query, args...) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } - if err != nil { - return nil, err - } - - for _, share := range dkgShares { - playerIdx, _, err := ocr2vrftypes.UnmarshalPlayerIdx(share.Dealer) - if err != nil { - return nil, errors.Wrapf(err, "unmarshalling %x", share.Dealer) - } - var h hash.Hash - if copied := copy(h[:], share.RecordHash); copied != 32 { - return nil, fmt.Errorf("wrong number of bytes copied in hash %x: %d", share.RecordHash, copied) - } - - // NOTE: no integrity check on share.MarshaledShareRecord - // because caller will do it anyways, so it'd be wasteful. - retrievedShares = append(retrievedShares, ocr2vrftypes.PersistentShareSetRecord{ - Dealer: *playerIdx, - MarshaledShareRecord: share.MarshaledShareRecord, - Hash: h, - }) - } - - lggr.Debugw("Read DKG shares from DB", - "shareRecords", shareHashes(retrievedShares), - "numRecords", len(dkgShares), - ) - - return retrievedShares, nil -} - -func shareHashes(shareRecords []ocr2vrftypes.PersistentShareSetRecord) []string { - r := make([]string, len(shareRecords)) - for i, record := range shareRecords { - r[i] = hexutil.Encode(record.Hash[:]) - } - return r -} diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go deleted file mode 100644 index 06f1bf3583f..00000000000 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package persistence - -import ( - "fmt" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/jmoiron/sqlx" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - "github.com/smartcontractkit/chainlink-vrf/types/hash" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -func setup(t testing.TB) (ocr2vrftypes.DKGSharePersistence, *sqlx.DB) { - db := pgtest.NewSqlxDB(t) - lggr := logger.TestLogger(t) - return NewShareDB(db, lggr, big.NewInt(1337), relay.NetworkEVM), db -} - -func TestShareDB_WriteShareRecords(t *testing.T) { - configDigest := testutils.Random32Byte() - keyID := testutils.Random32Byte() - - t.Run("valid input", func(tt *testing.T) { - shareDB, db := setup(tt) - var expectedRecords []ocr2vrftypes.PersistentShareSetRecord - - // Starting from 1 because player indexes must not be 0 - for i := 1; i < 4; i++ { - b := ocr2vrftypes.RawMarshalPlayerIdxInt(ocr2vrftypes.PlayerIdxInt(i)) - playerIdx, _, err := ocr2vrftypes.UnmarshalPlayerIdx(b) - require.NoError(t, err) - shareRecord := crypto.Keccak256Hash([]byte(fmt.Sprintf("%d", i))) - shareRecordHash := hash.GetHash(shareRecord[:]) - var h hash.Hash - copy(h[:], shareRecordHash[:]) - rec := ocr2vrftypes.PersistentShareSetRecord{ - Dealer: *playerIdx, - MarshaledShareRecord: shareRecord[:], - Hash: h, - } - expectedRecords = append(expectedRecords, rec) - } - - err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, expectedRecords) - require.NoError(tt, err) - - rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) - require.NoError(tt, err) - t.Cleanup(func() { assert.NoError(t, rows.Close()) }) - - var count int - for rows.Next() { - require.NoError(tt, rows.Scan(&count)) - } - require.NoError(tt, rows.Err()) - - require.Equal(tt, 3, count) - }) - - t.Run("bad input, zero hash", func(tt *testing.T) { - shareDB, db := setup(tt) - b := ocr2vrftypes.RawMarshalPlayerIdxInt(ocr2vrftypes.PlayerIdxInt(1)) - dealer, _, err := ocr2vrftypes.UnmarshalPlayerIdx(b) - require.NoError(tt, err) - records := []ocr2vrftypes.PersistentShareSetRecord{ - { - Dealer: *dealer, - MarshaledShareRecord: []byte{1}, - Hash: hash.Hash{}, // There's a problem here - }, - } - - // no error, but there will be no rows inserted in the db - err = shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, records) - require.NoError(tt, err) - - rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) - require.NoError(tt, err) - t.Cleanup(func() { assert.NoError(t, rows.Close()) }) - - var count int - for rows.Next() { - require.NoError(tt, rows.Scan(&count)) - } - require.NoError(tt, rows.Err()) - - require.Equal(tt, 0, count) - }) - - t.Run("bad input, nonmatching hash", func(tt *testing.T) { - shareDB, db := setup(tt) - var records []ocr2vrftypes.PersistentShareSetRecord - - // Starting from 1 because player indexes must not be 0 - for i := 1; i < 4; i++ { - b := ocr2vrftypes.RawMarshalPlayerIdxInt(ocr2vrftypes.PlayerIdxInt(i)) - playerIdx, _, err := ocr2vrftypes.UnmarshalPlayerIdx(b) - require.NoError(t, err) - shareRecord := crypto.Keccak256Hash([]byte(fmt.Sprintf("%d", i))) - // Expected hash is SHA256, not Keccak256. - shareRecordHash := crypto.Keccak256Hash(shareRecord[:]) - var h hash.Hash - copy(h[:], shareRecordHash[:]) - rec := ocr2vrftypes.PersistentShareSetRecord{ - Dealer: *playerIdx, - MarshaledShareRecord: shareRecord[:], - Hash: h, - } - records = append(records, rec) - } - - err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, records) - require.Error(tt, err) - - // no rows should have been inserted - rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) - require.NoError(tt, err) - t.Cleanup(func() { assert.NoError(t, rows.Close()) }) - - var count int - for rows.Next() { - require.NoError(tt, rows.Scan(&count)) - } - require.NoError(tt, rows.Err()) - - require.Equal(tt, 0, count) - }) -} - -func TestShareDBE2E(t *testing.T) { - shareDB, _ := setup(t) - - // create some fake data to insert and retrieve - configDigest := testutils.Random32Byte() - keyID := testutils.Random32Byte() - var expectedRecords []ocr2vrftypes.PersistentShareSetRecord - expectedRecordsMap := make(map[ocr2vrftypes.PlayerIdx]ocr2vrftypes.PersistentShareSetRecord) - - // Starting from 1 because player indexes must not be 0 - for i := 1; i < 4; i++ { - b := ocr2vrftypes.RawMarshalPlayerIdxInt(ocr2vrftypes.PlayerIdxInt(i)) - playerIdx, _, err := ocr2vrftypes.UnmarshalPlayerIdx(b) - require.NoError(t, err) - shareRecord := crypto.Keccak256Hash([]byte(fmt.Sprintf("%d", i))) - shareRecordHash := hash.GetHash(shareRecord[:]) - var h hash.Hash - copy(h[:], shareRecordHash[:]) - rec := ocr2vrftypes.PersistentShareSetRecord{ - Dealer: *playerIdx, - MarshaledShareRecord: shareRecord[:], - Hash: h, - } - expectedRecords = append(expectedRecords, rec) - expectedRecordsMap[*playerIdx] = rec - } - - err := shareDB.WriteShareRecords(testutils.Context(t), configDigest, keyID, expectedRecords) - require.NoError(t, err) - - actualRecords, err := shareDB.ReadShareRecords(configDigest, keyID) - require.NoError(t, err) - - assert.Equal(t, len(expectedRecords), len(actualRecords)) - numAssertions := 0 - for _, actualRecord := range actualRecords { - expectedRecord, ok := expectedRecordsMap[actualRecord.Dealer] - require.True(t, ok) - require.Equal(t, expectedRecord.MarshaledShareRecord, actualRecord.MarshaledShareRecord) - require.Equal(t, expectedRecord.Hash[:], actualRecord.Hash[:]) - numAssertions++ - } - - require.Equal(t, len(expectedRecords), numAssertions) -} diff --git a/core/services/ocr2/plugins/dkg/persistence/models.go b/core/services/ocr2/plugins/dkg/persistence/models.go deleted file mode 100644 index 02c63393a3b..00000000000 --- a/core/services/ocr2/plugins/dkg/persistence/models.go +++ /dev/null @@ -1,9 +0,0 @@ -package persistence - -type dkgShare struct { - ConfigDigest []byte `db:"config_digest"` - KeyID []byte `db:"key_id"` - Dealer []byte `db:"dealer"` - MarshaledShareRecord []byte `db:"marshaled_share_record"` - RecordHash []byte `db:"record_hash"` -} diff --git a/core/services/ocr2/plugins/dkg/plugin.go b/core/services/ocr2/plugins/dkg/plugin.go deleted file mode 100644 index 0364c5d9ab0..00000000000 --- a/core/services/ocr2/plugins/dkg/plugin.go +++ /dev/null @@ -1,96 +0,0 @@ -package dkg - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "math/big" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/libocr/commontypes" - libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - "github.com/smartcontractkit/chainlink-vrf/dkg" - - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" -) - -func NewDKGServices( - jb job.Job, - ocr2Provider evmrelay.DKGProvider, - lggr logger.Logger, - ocrLogger commontypes.Logger, - dkgSignKs keystore.DKGSign, - dkgEncryptKs keystore.DKGEncrypt, - ethClient evmclient.Client, - oracleArgsNoPlugin libocr2.OCR2OracleArgs, - ds sqlutil.DataSource, - chainID *big.Int, - network string, -) ([]job.ServiceCtx, error) { - var pluginConfig config.PluginConfig - err := json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &pluginConfig) - if err != nil { - return nil, errors.Wrap(err, "json unmarshal plugin config") - } - err = config.ValidatePluginConfig(pluginConfig, dkgSignKs, dkgEncryptKs) - if err != nil { - return nil, errors.Wrap(err, "validate plugin config") - } - signKey, err := dkgSignKs.Get(pluginConfig.SigningPublicKey) - if err != nil { - return nil, errors.Wrap(err, "get dkgsign key") - } - encryptKey, err := dkgEncryptKs.Get(pluginConfig.EncryptionPublicKey) - if err != nil { - return nil, errors.Wrap(err, "get dkgencrypt key") - } - onchainDKGClient, err := NewOnchainDKGClient( - jb.OCR2OracleSpec.ContractID, - ethClient) - if err != nil { - return nil, errors.Wrap(err, "new onchain dkg client") - } - onchainContract := dkg.NewOnchainContract(onchainDKGClient, &altbn_128.G2{}) - keyConsumer := newDummyKeyConsumer() - keyID, err := DecodeKeyID(pluginConfig.KeyID) - if err != nil { - return nil, errors.Wrap(err, "decode key ID") - } - shareDB := persistence.NewShareDB(ds, lggr.Named("DKGShareDB"), chainID, network) - oracleArgsNoPlugin.ReportingPluginFactory = dkg.NewReportingPluginFactory( - encryptKey.KyberScalar(), - signKey.KyberScalar(), - keyID, - onchainContract, - ocrLogger, - keyConsumer, - shareDB, - ) - oracle, err := libocr2.NewOracle(oracleArgsNoPlugin) - if err != nil { - return nil, errors.Wrap(err, "error calling NewOracle") - } - return []job.ServiceCtx{ocr2Provider, job.NewServiceAdapter(oracle)}, nil -} - -func DecodeKeyID(val string) (byteArray [32]byte, err error) { - decoded, err := hex.DecodeString(val) - if err != nil { - return [32]byte{}, errors.Wrap(err, "hex decode string") - } - if len(decoded) != 32 { - return [32]byte{}, fmt.Errorf("expected value to be 32 bytes but received %d bytes", len(decoded)) - } - copy(byteArray[:], decoded) - return -} diff --git a/core/services/ocr2/plugins/llo/helpers_test.go b/core/services/ocr2/plugins/llo/helpers_test.go index 20be811fa35..95e5502697b 100644 --- a/core/services/ocr2/plugins/llo/helpers_test.go +++ b/core/services/ocr2/plugins/llo/helpers_test.go @@ -59,7 +59,7 @@ type request struct { } func (r request) TransmitterID() ocr2types.Account { - return ocr2types.Account(r.pk.String()) + return ocr2types.Account(fmt.Sprintf("%x", r.pk)) } type mercuryServer struct { @@ -114,7 +114,7 @@ func startMercuryServer(t *testing.T, srv *mercuryServer, pubKeys []ed25519.Publ t.Fatalf("[MAIN] failed to listen: %v", err) } serverURL = lis.Addr().String() - s := wsrpc.NewServer(wsrpc.WithCreds(srv.privKey, pubKeys)) + s := wsrpc.NewServer(wsrpc.Creds(srv.privKey, pubKeys)) // Register mercury implementation with the wsrpc server pb.RegisterMercuryServer(s, srv) diff --git a/core/services/ocr2/plugins/llo/onchain_channel_definition_cache_integration_test.go b/core/services/ocr2/plugins/llo/onchain_channel_definition_cache_integration_test.go index a21a9dfc7d8..2a4d03befd9 100644 --- a/core/services/ocr2/plugins/llo/onchain_channel_definition_cache_integration_test.go +++ b/core/services/ocr2/plugins/llo/onchain_channel_definition_cache_integration_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/channel_config_store" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -84,8 +85,9 @@ func Test_ChannelDefinitionCache_Integration(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) lp := logpoller.NewLogPoller( - logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, lpOpts) + logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, ht, lpOpts) servicetest.Run(t, lp) cdc := llo.NewChannelDefinitionCache(lggr, orm, lp, configStoreAddress, 0) @@ -156,8 +158,9 @@ func Test_ChannelDefinitionCache_Integration(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) lp := &mockLogPoller{ - LogPoller: logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, lpOpts), + LogPoller: logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, ht, lpOpts), LatestBlockFn: func(ctx context.Context) (int64, error) { return 0, nil }, @@ -198,7 +201,8 @@ func Test_ChannelDefinitionCache_Integration(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr), ethClient, lggr, ht, lpOpts) servicetest.Run(t, lp) cdc := llo.NewChannelDefinitionCache(lggr, orm, lp, configStoreAddress, channel2Block.Number().Int64()+1) diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index 58bde79587e..904bb3c0f8e 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -104,7 +104,7 @@ func startMercuryServer(t *testing.T, srv *mercuryServer, pubKeys []ed25519.Publ t.Fatalf("[MAIN] failed to listen: %v", err) } serverURL = lis.Addr().String() - s := wsrpc.NewServer(wsrpc.WithCreds(srv.privKey, pubKeys)) + s := wsrpc.NewServer(wsrpc.Creds(srv.privKey, pubKeys)) // Register mercury implementation with the wsrpc server pb.RegisterMercuryServer(s, srv) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go index 0e2f87d0821..ccc0feffae7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go index ce7325a96be..0cddd434483 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry.go @@ -594,16 +594,21 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, keys []ocr2keepers.Upkee return nil, err } + args := []interface{}{ + map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + }, + } + + if opts.BlockNumber != nil { + args = append(args, hexutil.EncodeBig(opts.BlockNumber)) + } + var result string checkReqs[i] = rpc.BatchElem{ Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - }, - hexutil.EncodeBig(opts.BlockNumber), - }, + Args: args, Result: &result, } @@ -660,16 +665,21 @@ func (r *EvmRegistry) simulatePerformUpkeeps(ctx context.Context, checkResults [ return nil, err } + args := []interface{}{ + map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + }, + } + + if opts.BlockNumber != nil { + args = append(args, hexutil.EncodeBig(opts.BlockNumber)) + } + var result string performReqs = append(performReqs, rpc.BatchElem{ Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - }, - hexutil.EncodeBig(opts.BlockNumber), - }, + Args: args, Result: &result, }) @@ -726,16 +736,21 @@ func (r *EvmRegistry) getUpkeepConfigs(ctx context.Context, ids []*big.Int) ([]a return nil, fmt.Errorf("failed to pack id with abi: %s", err) } + args := []interface{}{ + map[string]interface{}{ + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + }, + } + + if opts.BlockNumber != nil { + args = append(args, hexutil.EncodeBig(opts.BlockNumber)) + } + var result string uReqs[i] = rpc.BatchElem{ Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - }, - hexutil.EncodeBig(opts.BlockNumber), - }, + Args: args, Result: &result, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go index 0e9badc2ac3..89c1ec6fd1f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks/upkeep_state_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go index fe15e962e53..e58d5ad9c93 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go @@ -1,7 +1,6 @@ package logprovider import ( - "math" "math/big" "sort" "sync" @@ -22,11 +21,11 @@ type LogBuffer interface { // given upkeep was exceeded. Returns the number of logs that were added and number of logs that were dropped. Enqueue(id *big.Int, logs ...logpoller.Log) (added int, dropped int) // Dequeue pulls logs from the buffer that are within the given block window, - // with a maximum number of logs per upkeep and a total maximum number of logs to return. - // It also accepts a function to select upkeeps. + // with a maximum number of logs to return. + // It also accepts a boolean to identify if we are operating under minimum dequeue. // Returns logs (associated to upkeeps) and the number of remaining // logs in that window for the involved upkeeps. - Dequeue(block int64, blockRate, upkeepLimit, maxResults int, upkeepSelector func(id *big.Int) bool) ([]BufferedLog, int) + Dequeue(startWindowBlock int64, maxResults int, minimumDequeue bool) ([]BufferedLog, int) // SetConfig sets the buffer size and the maximum number of logs to keep for each upkeep. SetConfig(lookback, blockRate, logLimit uint32) // NumOfUpkeeps returns the number of upkeeps that are being tracked by the buffer. @@ -35,10 +34,6 @@ type LogBuffer interface { SyncFilters(filterStore UpkeepFilterStore) error } -func DefaultUpkeepSelector(id *big.Int) bool { - return true -} - type logBufferOptions struct { // number of blocks to keep in the buffer lookback *atomic.Uint32 @@ -46,6 +41,8 @@ type logBufferOptions struct { blockRate *atomic.Uint32 // max number of logs to keep in the buffer for each upkeep per window (LogLimit*10) windowLimit *atomic.Uint32 + // number of logs we need to dequeue per upkeep per block window at a minimum + logLimit *atomic.Uint32 } func newLogBufferOptions(lookback, blockRate, logLimit uint32) *logBufferOptions { @@ -53,6 +50,7 @@ func newLogBufferOptions(lookback, blockRate, logLimit uint32) *logBufferOptions windowLimit: new(atomic.Uint32), lookback: new(atomic.Uint32), blockRate: new(atomic.Uint32), + logLimit: new(atomic.Uint32), } opts.override(lookback, blockRate, logLimit) @@ -63,10 +61,7 @@ func (o *logBufferOptions) override(lookback, blockRate, logLimit uint32) { o.windowLimit.Store(logLimit * 10) o.lookback.Store(lookback) o.blockRate.Store(blockRate) -} - -func (o *logBufferOptions) windows() int { - return int(math.Ceil(float64(o.lookback.Load()) / float64(o.blockRate.Load()))) + o.logLimit.Store(logLimit) } type logBuffer struct { @@ -75,21 +70,21 @@ type logBuffer struct { // last block number seen by the buffer lastBlockSeen *atomic.Int64 // map of upkeep id to its queue - queues map[string]*upkeepLogQueue - lock sync.RWMutex + queues map[string]*upkeepLogQueue + queueIDs []string + blockHashes map[int64]string - // map for then number of times we have enqueued logs for a block number - enqueuedBlocks map[int64]map[string]int - enqueuedBlockLock sync.RWMutex + lock sync.RWMutex } func NewLogBuffer(lggr logger.Logger, lookback, blockRate, logLimit uint32) LogBuffer { return &logBuffer{ - lggr: lggr.Named("KeepersRegistry.LogEventBufferV1"), - opts: newLogBufferOptions(lookback, blockRate, logLimit), - lastBlockSeen: new(atomic.Int64), - enqueuedBlocks: map[int64]map[string]int{}, - queues: make(map[string]*upkeepLogQueue), + lggr: lggr.Named("KeepersRegistry.LogEventBufferV1"), + opts: newLogBufferOptions(lookback, blockRate, logLimit), + lastBlockSeen: new(atomic.Int64), + queueIDs: []string{}, + blockHashes: map[int64]string{}, + queues: make(map[string]*upkeepLogQueue), } } @@ -99,67 +94,64 @@ func NewLogBuffer(lggr logger.Logger, lookback, blockRate, logLimit uint32) LogB // All logs for an upkeep on a particular block will be enqueued in a single Enqueue call. // Returns the number of logs that were added and number of logs that were dropped. func (b *logBuffer) Enqueue(uid *big.Int, logs ...logpoller.Log) (int, int) { + b.lock.Lock() + defer b.lock.Unlock() + buf, ok := b.getUpkeepQueue(uid) if !ok || buf == nil { buf = newUpkeepLogQueue(b.lggr, uid, b.opts) b.setUpkeepQueue(uid, buf) } - latestLogBlock, uniqueBlocks := blockStatistics(logs...) + latestLogBlock, reorgBlocks := b.blockStatistics(logs...) + + if len(reorgBlocks) > 0 { + b.evictReorgdLogs(reorgBlocks) + } + if lastBlockSeen := b.lastBlockSeen.Load(); lastBlockSeen < latestLogBlock { b.lastBlockSeen.Store(latestLogBlock) } else if latestLogBlock < lastBlockSeen { b.lggr.Debugw("enqueuing logs with a latest block older older than latest seen block", "logBlock", latestLogBlock, "lastBlockSeen", lastBlockSeen) } - b.trackBlockNumbersForUpkeep(uid, uniqueBlocks) - blockThreshold := b.lastBlockSeen.Load() - int64(b.opts.lookback.Load()) + blockThreshold, _ = getBlockWindow(blockThreshold, int(b.opts.blockRate.Load())) if blockThreshold <= 0 { blockThreshold = 1 } - b.cleanupEnqueuedBlocks(blockThreshold) - return buf.enqueue(blockThreshold, logs...) } -func (b *logBuffer) cleanupEnqueuedBlocks(blockThreshold int64) { - b.enqueuedBlockLock.Lock() - defer b.enqueuedBlockLock.Unlock() - // clean up enqueued block counts - for block := range b.enqueuedBlocks { - if block < blockThreshold { - delete(b.enqueuedBlocks, block) +// blockStatistics returns the latest block number from the given logs, and updates any blocks that have been reorgd +func (b *logBuffer) blockStatistics(logs ...logpoller.Log) (int64, map[int64]bool) { + var latest int64 + reorgBlocks := map[int64]bool{} + + for _, l := range logs { + if l.BlockNumber > latest { + latest = l.BlockNumber } + if hash, ok := b.blockHashes[l.BlockNumber]; ok { + if hash != l.BlockHash.String() { + reorgBlocks[l.BlockNumber] = true + b.lggr.Debugw("encountered reorgd block", "blockNumber", l.BlockNumber) + } + } + b.blockHashes[l.BlockNumber] = l.BlockHash.String() } -} -// trackBlockNumbersForUpkeep keeps track of the number of times we enqueue logs for an upkeep, -// for a specific block number. The expectation is that we will only enqueue logs for an upkeep for a -// specific block number once, i.e. all logs for an upkeep for a block, will be enqueued in a single -// enqueue call. In the event that we see upkeep logs enqueued for a particular block more than once, -// we log a message. -func (b *logBuffer) trackBlockNumbersForUpkeep(uid *big.Int, uniqueBlocks map[int64]bool) { - b.enqueuedBlockLock.Lock() - defer b.enqueuedBlockLock.Unlock() - - if uid == nil { - return - } + return latest, reorgBlocks +} - for blockNumber := range uniqueBlocks { - if blockNumbers, ok := b.enqueuedBlocks[blockNumber]; ok { - if upkeepBlockInstances, ok := blockNumbers[uid.String()]; ok { - blockNumbers[uid.String()] = upkeepBlockInstances + 1 - b.lggr.Debugw("enqueuing logs again for a previously seen block for this upkeep", "blockNumber", blockNumber, "numberOfEnqueues", b.enqueuedBlocks[blockNumber], "upkeepID", uid.String()) - } else { - blockNumbers[uid.String()] = 1 - } - b.enqueuedBlocks[blockNumber] = blockNumbers - } else { - b.enqueuedBlocks[blockNumber] = map[string]int{ - uid.String(): 1, +func (b *logBuffer) evictReorgdLogs(reorgBlocks map[int64]bool) { + for blockNumber := range reorgBlocks { + start, _ := getBlockWindow(blockNumber, int(b.opts.blockRate.Load())) + for _, queue := range b.queues { + if _, ok := queue.logs[blockNumber]; ok { + queue.logs[blockNumber] = []logpoller.Log{} + queue.dequeued[start] = 0 } } } @@ -167,27 +159,36 @@ func (b *logBuffer) trackBlockNumbersForUpkeep(uid *big.Int, uniqueBlocks map[in // Dequeue greedly pulls logs from the buffers. // Returns logs and the number of remaining logs in the buffer. -func (b *logBuffer) Dequeue(block int64, blockRate, upkeepLimit, maxResults int, upkeepSelector func(id *big.Int) bool) ([]BufferedLog, int) { +func (b *logBuffer) Dequeue(startWindowBlock int64, maxResults int, bestEffort bool) ([]BufferedLog, int) { b.lock.RLock() defer b.lock.RUnlock() - start, end := getBlockWindow(block, blockRate) - return b.dequeue(start, end, upkeepLimit, maxResults, upkeepSelector) + return b.dequeue(startWindowBlock, maxResults, bestEffort) } -// dequeue pulls logs from the buffers, depends the given selector (upkeepSelector), -// in block range [start,end] with minimum number of results per upkeep (upkeepLimit) -// and the maximum number of results (capacity). +// dequeue pulls logs from the buffers, in block range [start,end] with minimum number +// of results per upkeep (upkeepLimit) and the maximum number of results (capacity). +// If operating under minimum dequeue, upkeeps are skipped when the minimum number +// of logs have been dequeued for that upkeep. // Returns logs and the number of remaining logs in the buffer for the given range and selector. // NOTE: this method is not thread safe and should be called within a lock. -func (b *logBuffer) dequeue(start, end int64, upkeepLimit, capacity int, upkeepSelector func(id *big.Int) bool) ([]BufferedLog, int) { +func (b *logBuffer) dequeue(start int64, capacity int, minimumDequeue bool) ([]BufferedLog, int) { var result []BufferedLog var remainingLogs int - for _, q := range b.queues { - if !upkeepSelector(q.id) { - // if the upkeep is not selected, skip it + minimumDequeueMet := 0 + + logLimit := int(b.opts.logLimit.Load()) + end := start + int64(b.opts.blockRate.Load()) + + for _, qid := range b.queueIDs { + q := b.queues[qid] + + if minimumDequeue && q.dequeued[start] >= logLimit { + // if we have already dequeued the minimum commitment for this window, skip it + minimumDequeueMet++ continue } + logsInRange := q.sizeOfRange(start, end) if logsInRange == 0 { // if there are no logs in the range, skip the upkeep @@ -198,17 +199,26 @@ func (b *logBuffer) dequeue(start, end int64, upkeepLimit, capacity int, upkeepS remainingLogs += logsInRange continue } - if upkeepLimit > capacity { - // adjust limit if it is higher than the actual capacity - upkeepLimit = capacity + + var logs []logpoller.Log + remaining := 0 + + if minimumDequeue { + logs, remaining = q.dequeue(start, end, min(capacity, logLimit-q.dequeued[start])) + } else { + logs, remaining = q.dequeue(start, end, capacity) } - logs, remaining := q.dequeue(start, end, upkeepLimit) + for _, l := range logs { result = append(result, BufferedLog{ID: q.id, Log: l}) capacity-- } remainingLogs += remaining + + // update the buffer with how many logs we have dequeued for this window + q.dequeued[start] += len(logs) } + b.lggr.Debugw("minimum commitment logs dequeued", "start", start, "end", end, "numUpkeeps", len(b.queues), "minimumDequeueMet", minimumDequeueMet) return result, remainingLogs } @@ -230,30 +240,34 @@ func (b *logBuffer) SyncFilters(filterStore UpkeepFilterStore) error { b.lock.Lock() defer b.lock.Unlock() - for upkeepID := range b.queues { + var newQueueIDs []string + + for _, upkeepID := range b.queueIDs { uid := new(big.Int) _, ok := uid.SetString(upkeepID, 10) if ok && !filterStore.Has(uid) { // remove upkeep that is not in the filter store delete(b.queues, upkeepID) + } else { + newQueueIDs = append(newQueueIDs, upkeepID) } } + b.queueIDs = newQueueIDs + return nil } func (b *logBuffer) getUpkeepQueue(uid *big.Int) (*upkeepLogQueue, bool) { - b.lock.RLock() - defer b.lock.RUnlock() - ub, ok := b.queues[uid.String()] return ub, ok } func (b *logBuffer) setUpkeepQueue(uid *big.Int, buf *upkeepLogQueue) { - b.lock.Lock() - defer b.lock.Unlock() - + if _, ok := b.queues[uid.String()]; !ok { + b.queueIDs = append(b.queueIDs, uid.String()) + sort.Slice(b.queueIDs, func(i, j int) bool { return b.queueIDs[i] < b.queueIDs[j] }) + } b.queues[uid.String()] = buf } @@ -287,21 +301,25 @@ type upkeepLogQueue struct { opts *logBufferOptions // logs is the buffer of logs for the upkeep - logs []logpoller.Log + logs map[int64][]logpoller.Log + blockNumbers []int64 + // states keeps track of the state of the logs that are known to the queue // and the block number they were seen at - states map[string]logTriggerStateEntry - lock sync.RWMutex + states map[string]logTriggerStateEntry + dequeued map[int64]int + lock sync.RWMutex } func newUpkeepLogQueue(lggr logger.Logger, id *big.Int, opts *logBufferOptions) *upkeepLogQueue { - maxLogs := int(opts.windowLimit.Load()) * opts.windows() // limit per window * windows return &upkeepLogQueue{ - lggr: lggr.With("upkeepID", id.String()), - id: id, - opts: opts, - logs: make([]logpoller.Log, 0, maxLogs), - states: make(map[string]logTriggerStateEntry), + lggr: lggr.With("upkeepID", id.String()), + id: id, + opts: opts, + logs: map[int64][]logpoller.Log{}, + blockNumbers: make([]int64, 0), + states: make(map[string]logTriggerStateEntry), + dequeued: map[int64]int{}, } } @@ -311,9 +329,9 @@ func (q *upkeepLogQueue) sizeOfRange(start, end int64) int { defer q.lock.RUnlock() size := 0 - for _, l := range q.logs { - if l.BlockNumber >= start && l.BlockNumber <= end { - size++ + for blockNumber, logs := range q.logs { + if blockNumber >= start && blockNumber <= end { + size += len(logs) } } return size @@ -331,9 +349,11 @@ func (q *upkeepLogQueue) dequeue(start, end int64, limit int) ([]logpoller.Log, var results []logpoller.Log var remaining int - updatedLogs := make([]logpoller.Log, 0) - for _, l := range q.logs { - if l.BlockNumber >= start && l.BlockNumber <= end { + + for blockNumber := start; blockNumber <= end; blockNumber++ { + updatedLogs := make([]logpoller.Log, 0) + blockResults := 0 + for _, l := range q.logs[blockNumber] { if len(results) < limit { results = append(results, l) lid := logID(l) @@ -341,15 +361,18 @@ func (q *upkeepLogQueue) dequeue(start, end int64, limit int) ([]logpoller.Log, s.state = logTriggerStateDequeued q.states[lid] = s } - continue + blockResults++ + } else { + remaining++ + updatedLogs = append(updatedLogs, l) } - remaining++ } - updatedLogs = append(updatedLogs, l) + if blockResults > 0 { + q.logs[blockNumber] = updatedLogs + } } if len(results) > 0 { - q.logs = updatedLogs q.lggr.Debugw("Dequeued logs", "start", start, "end", end, "limit", limit, "results", len(results), "remaining", remaining) } @@ -362,10 +385,6 @@ func (q *upkeepLogQueue) dequeue(start, end int64, limit int) ([]logpoller.Log, // given upkeep was exceeded. Additionally, it will drop logs that are older than blockThreshold. // Returns the number of logs that were added and number of logs that were dropped. func (q *upkeepLogQueue) enqueue(blockThreshold int64, logsToAdd ...logpoller.Log) (int, int) { - q.lock.Lock() - defer q.lock.Unlock() - - logs := q.logs var added int for _, log := range logsToAdd { if log.BlockNumber < blockThreshold { @@ -379,9 +398,15 @@ func (q *upkeepLogQueue) enqueue(blockThreshold int64, logsToAdd ...logpoller.Lo } q.states[lid] = logTriggerStateEntry{state: logTriggerStateEnqueued, block: log.BlockNumber} added++ - logs = append(logs, log) + if logList, ok := q.logs[log.BlockNumber]; ok { + logList = append(logList, log) + q.logs[log.BlockNumber] = logList + } else { + q.logs[log.BlockNumber] = []logpoller.Log{log} + q.blockNumbers = append(q.blockNumbers, log.BlockNumber) + sort.Slice(q.blockNumbers, func(i, j int) bool { return q.blockNumbers[i] < q.blockNumbers[j] }) + } } - q.logs = logs var dropped int if added > 0 { @@ -402,70 +427,99 @@ func (q *upkeepLogQueue) orderLogs() { // sort logs by block number, tx hash and log index // to keep the q sorted and to ensure that logs can be // grouped by block windows for the cleanup - sort.SliceStable(q.logs, func(i, j int) bool { - return LogSorter(q.logs[i], q.logs[j]) - }) + for _, blockNumber := range q.blockNumbers { + toSort := q.logs[blockNumber] + sort.SliceStable(toSort, func(i, j int) bool { + return LogSorter(toSort[i], toSort[j]) + }) + q.logs[blockNumber] = toSort + } } // clean removes logs that are older than blockThreshold and drops logs if the limit for the // given upkeep was exceeded. Returns the number of logs that were dropped. // NOTE: this method is not thread safe and should be called within a lock. func (q *upkeepLogQueue) clean(blockThreshold int64) int { - var dropped, expired int + var totalDropped int + blockRate := int(q.opts.blockRate.Load()) windowLimit := int(q.opts.windowLimit.Load()) - updated := make([]logpoller.Log, 0) // helper variables to keep track of the current window capacity currentWindowCapacity, currentWindowStart := 0, int64(0) - for _, l := range q.logs { - if blockThreshold > l.BlockNumber { // old log, removed - prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionExpired).Inc() - // q.lggr.Debugw("Expiring old log", "blockNumber", l.BlockNumber, "blockThreshold", blockThreshold, "logIndex", l.LogIndex) - logid := logID(l) - delete(q.states, logid) - expired++ - continue - } - start, _ := getBlockWindow(l.BlockNumber, blockRate) - if start != currentWindowStart { - // new window, reset capacity - currentWindowStart = start - currentWindowCapacity = 0 + oldBlockNumbers := make([]int64, 0) + blockNumbers := make([]int64, 0) + + for _, blockNumber := range q.blockNumbers { + var dropped, expired int + + logs := q.logs[blockNumber] + updated := make([]logpoller.Log, 0) + + if blockThreshold > blockNumber { + oldBlockNumbers = append(oldBlockNumbers, blockNumber) + } else { + blockNumbers = append(blockNumbers, blockNumber) } - currentWindowCapacity++ - // if capacity has been reached, drop the log - if currentWindowCapacity > windowLimit { - lid := logID(l) - if s, ok := q.states[lid]; ok { - s.state = logTriggerStateDropped - q.states[lid] = s + + for _, l := range logs { + if blockThreshold > l.BlockNumber { // old log, removed + prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionExpired).Inc() + // q.lggr.Debugw("Expiring old log", "blockNumber", l.BlockNumber, "blockThreshold", blockThreshold, "logIndex", l.LogIndex) + logid := logID(l) + delete(q.states, logid) + expired++ + continue + } + start, _ := getBlockWindow(l.BlockNumber, blockRate) + if start != currentWindowStart { + // new window, reset capacity + currentWindowStart = start + currentWindowCapacity = 0 } - dropped++ - prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionDropped).Inc() - q.lggr.Debugw("Reached log buffer limits, dropping log", "blockNumber", l.BlockNumber, - "blockHash", l.BlockHash, "txHash", l.TxHash, "logIndex", l.LogIndex, "len updated", len(updated), - "currentWindowStart", currentWindowStart, "currentWindowCapacity", currentWindowCapacity, - "maxLogsPerWindow", windowLimit, "blockRate", blockRate) + currentWindowCapacity++ + // if capacity has been reached, drop the log + if currentWindowCapacity > windowLimit { + lid := logID(l) + if s, ok := q.states[lid]; ok { + s.state = logTriggerStateDropped + q.states[lid] = s + } + dropped++ + prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionDropped).Inc() + q.lggr.Debugw("Reached log buffer limits, dropping log", "blockNumber", l.BlockNumber, + "blockHash", l.BlockHash, "txHash", l.TxHash, "logIndex", l.LogIndex, "len updated", len(updated), + "currentWindowStart", currentWindowStart, "currentWindowCapacity", currentWindowCapacity, + "maxLogsPerWindow", windowLimit, "blockRate", blockRate) + continue + } + updated = append(updated, l) + } + + if dropped > 0 || expired > 0 { + totalDropped += dropped + q.logs[blockNumber] = updated + q.lggr.Debugw("Cleaned logs", "dropped", dropped, "expired", expired, "blockThreshold", blockThreshold, "len updated", len(updated), "len before", len(q.logs)) continue } - updated = append(updated, l) } - if dropped > 0 || expired > 0 { - q.lggr.Debugw("Cleaned logs", "dropped", dropped, "expired", expired, "blockThreshold", blockThreshold, "len updated", len(updated), "len before", len(q.logs)) - q.logs = updated + for _, blockNumber := range oldBlockNumbers { + delete(q.logs, blockNumber) + startWindow, _ := getBlockWindow(blockNumber, int(q.opts.blockRate.Load())) + delete(q.dequeued, startWindow) } + q.blockNumbers = blockNumbers q.cleanStates(blockThreshold) - return dropped + return totalDropped } // cleanStates removes states that are older than blockThreshold. // NOTE: this method is not thread safe and should be called within a lock. func (q *upkeepLogQueue) cleanStates(blockThreshold int64) { for lid, s := range q.states { - if s.block <= blockThreshold { + if s.block < blockThreshold { delete(q.states, lid) } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go index c41dd3d9bcc..f742d39689c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go @@ -23,12 +23,12 @@ func TestLogEventBufferV1(t *testing.T) { logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x2"), LogIndex: 0}, logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x1"), LogIndex: 2}, ) - results, remaining := buf.Dequeue(int64(1), 10, 1, 2, DefaultUpkeepSelector) + results, remaining := buf.Dequeue(int64(1), 2, true) require.Equal(t, 2, len(results)) require.Equal(t, 2, remaining) require.True(t, results[0].ID.Cmp(results[1].ID) != 0) - results, remaining = buf.Dequeue(int64(1), 10, 1, 2, DefaultUpkeepSelector) - require.Equal(t, 2, len(results)) + results, remaining = buf.Dequeue(int64(1), 2, true) + require.Equal(t, 0, len(results)) require.Equal(t, 0, remaining) } @@ -97,8 +97,6 @@ func TestLogEventBufferV1_EnqueueViolations(t *testing.T) { logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x2"), LogIndex: 0}, ) - assert.Equal(t, 1, buf.enqueuedBlocks[2]["1"]) - assert.Equal(t, 1, buf.enqueuedBlocks[1]["2"]) assert.True(t, true, logReceived) }) @@ -134,9 +132,6 @@ func TestLogEventBufferV1_EnqueueViolations(t *testing.T) { logpoller.Log{BlockNumber: 3, TxHash: common.HexToHash("0x3b"), LogIndex: 0}, ) - assert.Equal(t, 1, buf.enqueuedBlocks[2]["2"]) - assert.Equal(t, 1, buf.enqueuedBlocks[1]["1"]) - assert.Equal(t, 2, buf.enqueuedBlocks[3]["3"]) assert.True(t, true, logReceived) }) } @@ -153,7 +148,7 @@ func TestLogEventBufferV1_Dequeue(t *testing.T) { { name: "empty", logsInBuffer: map[*big.Int][]logpoller.Log{}, - args: newDequeueArgs(10, 1, 1, 10, nil), + args: newDequeueArgs(10, 1, 1, 10), lookback: 20, results: []logpoller.Log{}, }, @@ -165,7 +160,7 @@ func TestLogEventBufferV1_Dequeue(t *testing.T) { {BlockNumber: 14, TxHash: common.HexToHash("0x15"), LogIndex: 1}, }, }, - args: newDequeueArgs(10, 5, 3, 10, nil), + args: newDequeueArgs(10, 5, 3, 10), lookback: 20, results: []logpoller.Log{ {}, {}, @@ -191,7 +186,7 @@ func TestLogEventBufferV1_Dequeue(t *testing.T) { {BlockNumber: 14, TxHash: common.HexToHash("0x14"), LogIndex: 12}, }, }, - args: newDequeueArgs(10, 5, 2, 10, nil), + args: newDequeueArgs(10, 5, 2, 10), lookback: 20, results: []logpoller.Log{ {}, {}, {}, {}, @@ -204,25 +199,13 @@ func TestLogEventBufferV1_Dequeue(t *testing.T) { big.NewInt(1): append(createDummyLogSequence(2, 0, 12, common.HexToHash("0x12")), createDummyLogSequence(2, 0, 13, common.HexToHash("0x13"))...), big.NewInt(2): append(createDummyLogSequence(2, 10, 12, common.HexToHash("0x12")), createDummyLogSequence(2, 10, 13, common.HexToHash("0x13"))...), }, - args: newDequeueArgs(10, 5, 3, 4, nil), + args: newDequeueArgs(10, 5, 3, 4), lookback: 20, results: []logpoller.Log{ {}, {}, {}, {}, }, remaining: 4, }, - { - name: "with upkeep selector", - logsInBuffer: map[*big.Int][]logpoller.Log{ - big.NewInt(1): { - {BlockNumber: 12, TxHash: common.HexToHash("0x12"), LogIndex: 0}, - {BlockNumber: 14, TxHash: common.HexToHash("0x15"), LogIndex: 1}, - }, - }, - args: newDequeueArgs(10, 5, 5, 10, func(id *big.Int) bool { return false }), - lookback: 20, - results: []logpoller.Log{}, - }, } for _, tc := range tests { @@ -232,7 +215,9 @@ func TestLogEventBufferV1_Dequeue(t *testing.T) { added, dropped := buf.Enqueue(id, logs...) require.Equal(t, len(logs), added+dropped) } - results, remaining := buf.Dequeue(tc.args.block, tc.args.blockRate, tc.args.upkeepLimit, tc.args.maxResults, tc.args.upkeepSelector) + start, _ := getBlockWindow(tc.args.block, tc.args.blockRate) + + results, remaining := buf.Dequeue(start, tc.args.maxResults, true) require.Equal(t, len(tc.results), len(results)) require.Equal(t, tc.remaining, remaining) }) @@ -518,25 +503,20 @@ func TestLogEventBufferV1_BlockWindow(t *testing.T) { } type dequeueArgs struct { - block int64 - blockRate int - upkeepLimit int - maxResults int - upkeepSelector func(id *big.Int) bool + block int64 + blockRate int + upkeepLimit int + maxResults int } -func newDequeueArgs(block int64, blockRate int, upkeepLimit int, maxResults int, upkeepSelector func(id *big.Int) bool) dequeueArgs { +func newDequeueArgs(block int64, blockRate int, upkeepLimit int, maxResults int) dequeueArgs { args := dequeueArgs{ - block: block, - blockRate: blockRate, - upkeepLimit: upkeepLimit, - maxResults: maxResults, - upkeepSelector: upkeepSelector, + block: block, + blockRate: blockRate, + upkeepLimit: upkeepLimit, + maxResults: maxResults, } - if upkeepSelector == nil { - args.upkeepSelector = DefaultUpkeepSelector - } if blockRate == 0 { args.blockRate = 1 } @@ -561,107 +541,3 @@ func createDummyLogSequence(n, startIndex int, block int64, tx common.Hash) []lo } return logs } - -func Test_trackBlockNumbersForUpkeep(t *testing.T) { - buf := NewLogBuffer(logger.TestLogger(t), 10, 20, 1) - - logBuffer := buf.(*logBuffer) - - for _, tc := range []struct { - uid *big.Int - uniqueBlocks map[int64]bool - wantEnqueuedBlocks map[int64]map[string]int - }{ - { - uid: big.NewInt(1), - uniqueBlocks: map[int64]bool{ - 1: true, - 2: true, - 3: true, - }, - wantEnqueuedBlocks: map[int64]map[string]int{ - 1: { - "1": 1, - }, - 2: { - "1": 1, - }, - 3: { - "1": 1, - }, - }, - }, - { - uid: big.NewInt(2), - uniqueBlocks: map[int64]bool{ - 1: true, - 2: true, - 3: true, - }, - wantEnqueuedBlocks: map[int64]map[string]int{ - 1: { - "1": 1, - "2": 1, - }, - 2: { - "1": 1, - "2": 1, - }, - 3: { - "1": 1, - "2": 1, - }, - }, - }, - { - uid: big.NewInt(2), - uniqueBlocks: map[int64]bool{ - 3: true, - 4: true, - }, - wantEnqueuedBlocks: map[int64]map[string]int{ - 1: { - "1": 1, - "2": 1, - }, - 2: { - "1": 1, - "2": 1, - }, - 3: { - "1": 1, - "2": 2, - }, - 4: { - "2": 1, - }, - }, - }, - { - uniqueBlocks: map[int64]bool{ - 3: true, - 4: true, - }, - wantEnqueuedBlocks: map[int64]map[string]int{ - 1: { - "1": 1, - "2": 1, - }, - 2: { - "1": 1, - "2": 1, - }, - 3: { - "1": 1, - "2": 2, - }, - 4: { - "2": 1, - }, - }, - }, - } { - logBuffer.trackBlockNumbersForUpkeep(tc.uid, tc.uniqueBlocks) - assert.Equal(t, tc.wantEnqueuedBlocks, logBuffer.enqueuedBlocks) - } -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go index 64833f9269b..19302624b49 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go @@ -63,7 +63,7 @@ func NewOptions(finalityDepth int64, chainID *big.Int) LogTriggersOptions { // NOTE: o.LookbackBlocks should be set only from within tests func (o *LogTriggersOptions) Defaults(finalityDepth int64) { if o.LookbackBlocks == 0 { - lookbackBlocks := int64(200) + lookbackBlocks := int64(100) if lookbackBlocks < finalityDepth { lookbackBlocks = finalityDepth } @@ -86,7 +86,7 @@ func (o *LogTriggersOptions) Defaults(finalityDepth int64) { func (o *LogTriggersOptions) defaultBlockRate() uint32 { switch o.chainID.Int64() { case 42161, 421613, 421614: // Arbitrum - return 4 + return 2 default: return 1 } @@ -94,13 +94,11 @@ func (o *LogTriggersOptions) defaultBlockRate() uint32 { func (o *LogTriggersOptions) defaultLogLimit() uint32 { switch o.chainID.Int64() { - case 42161, 421613, 421614: // Arbitrum - return 1 case 1, 4, 5, 42, 11155111: // Eth return 20 case 10, 420, 56, 97, 137, 80001, 43113, 43114, 8453, 84531: // Optimism, BSC, Polygon, Avax, Base return 5 default: - return 2 + return 1 } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go index fc7504857ee..b1703321711 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go @@ -16,10 +16,12 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -505,7 +507,8 @@ func setupDependencies(t *testing.T, db *sqlx.DB, backend *simulated.Backend) (l RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(lorm, ethClient, pollerLggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(lorm, ethClient, pollerLggr, ht, lpOpts) return lp, ethClient } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log.go index 9603d6da5be..ba577f57130 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/log.go @@ -56,18 +56,3 @@ func logID(l logpoller.Log) string { copy(ext.BlockHash[:], l.BlockHash[:]) return hex.EncodeToString(ext.LogIdentifier()) } - -// blockStatistics returns the latest block number from the given logs, and a map of unique block numbers -func blockStatistics(logs ...logpoller.Log) (int64, map[int64]bool) { - var latest int64 - uniqueBlocks := map[int64]bool{} - - for _, l := range logs { - if l.BlockNumber > latest { - latest = l.BlockNumber - } - uniqueBlocks[l.BlockNumber] = true - } - - return latest, uniqueBlocks -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go index 633188c8396..3609d0a4654 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go @@ -48,8 +48,6 @@ var ( readerThreads = 4 bufferSyncInterval = 10 * time.Minute - // logLimitMinimum is how low the log limit can go. - logLimitMinimum = 1 ) // LogTriggerConfig is an alias for log trigger config. @@ -253,29 +251,6 @@ func (p *logEventProvider) createPayload(id *big.Int, log logpoller.Log) (ocr2ke return payload, nil } -// getBufferDequeueArgs returns the arguments for the buffer to dequeue logs. -// It adjust the log limit low based on the number of upkeeps to ensure that more upkeeps get slots in the result set. -func (p *logEventProvider) getBufferDequeueArgs() (blockRate, logLimitLow, maxResults, numOfUpkeeps int) { - blockRate, logLimitLow, maxResults, numOfUpkeeps = int(p.opts.BlockRate), int(p.opts.LogLimit), MaxPayloads, p.bufferV1.NumOfUpkeeps() - // in case we have more upkeeps than the max results, we reduce the log limit low - // so that more upkeeps will get slots in the result set. - for numOfUpkeeps > maxResults/logLimitLow { - if logLimitLow == logLimitMinimum { - // Log limit low can't go less than logLimitMinimum (1). - // If some upkeeps are not getting slots in the result set, they supposed to be picked up - // in the next iteration if the range is still applicable. - // TODO: alerts to notify the system is at full capacity. - // TODO: handle this case properly by distributing available slots across upkeeps to avoid - // starvation when log volume is high. - p.lggr.Warnw("The system is at full capacity", "maxResults", maxResults, "numOfUpkeeps", numOfUpkeeps, "logLimitLow", logLimitLow) - break - } - p.lggr.Debugw("Too many upkeeps, reducing the log limit low", "maxResults", maxResults, "numOfUpkeeps", numOfUpkeeps, "logLimitLow_before", logLimitLow) - logLimitLow-- - } - return -} - func (p *logEventProvider) getLogsFromBuffer(latestBlock int64) []ocr2keepers.UpkeepPayload { var payloads []ocr2keepers.UpkeepPayload @@ -286,25 +261,11 @@ func (p *logEventProvider) getLogsFromBuffer(latestBlock int64) []ocr2keepers.Up switch p.opts.BufferVersion { case BufferVersionV1: - // in v1, we use a greedy approach - we keep dequeuing logs until we reach the max results or cover the entire range. - blockRate, logLimitLow, maxResults, _ := p.getBufferDequeueArgs() - for len(payloads) < maxResults && start <= latestBlock { - logs, remaining := p.bufferV1.Dequeue(start, blockRate, logLimitLow, maxResults-len(payloads), DefaultUpkeepSelector) - if len(logs) > 0 { - p.lggr.Debugw("Dequeued logs", "start", start, "latestBlock", latestBlock, "logs", len(logs)) - } - for _, l := range logs { - payload, err := p.createPayload(l.ID, l.Log) - if err == nil { - payloads = append(payloads, payload) - } - } - if remaining > 0 { - p.lggr.Debugw("Remaining logs", "start", start, "latestBlock", latestBlock, "remaining", remaining) - // TODO: handle remaining logs in a better way than consuming the entire window, e.g. do not repeat more than x times - continue - } - start += int64(blockRate) + payloads = p.minimumCommitmentDequeue(latestBlock, start) + + // if we have remaining capacity following minimum commitment dequeue, perform a best effort dequeue + if len(payloads) < MaxPayloads { + payloads = p.bestEffortDequeue(latestBlock, start, payloads) } default: logs := p.buffer.dequeueRange(start, latestBlock, AllowedLogsPerUpkeep, MaxPayloads) @@ -319,6 +280,59 @@ func (p *logEventProvider) getLogsFromBuffer(latestBlock int64) []ocr2keepers.Up return payloads } +// minimumCommitmentDequeue dequeues the minimum number of logs per upkeep per block window, when available. +func (p *logEventProvider) minimumCommitmentDequeue(latestBlock, start int64) []ocr2keepers.UpkeepPayload { + var payloads []ocr2keepers.UpkeepPayload + + blockRate := int(p.opts.BlockRate) + + for len(payloads) < MaxPayloads && start <= latestBlock { + startWindow, _ := getBlockWindow(start, blockRate) + + // dequeue the minimum number logs (log limit, varies by chain) per upkeep for this block window + logs, remaining := p.bufferV1.Dequeue(startWindow, MaxPayloads-len(payloads), true) + if len(logs) > 0 { + p.lggr.Debugw("minimum commitment dequeue", "start", start, "latestBlock", latestBlock, "logs", len(logs), "remaining", remaining) + } + for _, l := range logs { + payload, err := p.createPayload(l.ID, l.Log) + if err == nil { + payloads = append(payloads, payload) + } + } + + start += int64(blockRate) + } + + return payloads +} + +// bestEffortDequeue dequeues the remaining logs from the buffer, after the minimum number of logs +// have been dequeued for every upkeep in every block window. +func (p *logEventProvider) bestEffortDequeue(latestBlock, start int64, payloads []ocr2keepers.UpkeepPayload) []ocr2keepers.UpkeepPayload { + blockRate := int(p.opts.BlockRate) + + for len(payloads) < MaxPayloads && start <= latestBlock { + startWindow, _ := getBlockWindow(start, blockRate) + + // dequeue as many logs as we can, based on remaining capacity, for this block window + logs, remaining := p.bufferV1.Dequeue(startWindow, MaxPayloads-len(payloads), false) + if len(logs) > 0 { + p.lggr.Debugw("best effort dequeue", "start", start, "latestBlock", latestBlock, "logs", len(logs), "remaining", remaining) + } + for _, l := range logs { + payload, err := p.createPayload(l.ID, l.Log) + if err == nil { + payloads = append(payloads, payload) + } + } + + start += int64(blockRate) + } + + return payloads +} + // ReadLogs fetches the logs for the given upkeeps. func (p *logEventProvider) ReadLogs(pctx context.Context, ids ...*big.Int) error { ctx, cancel := context.WithTimeout(pctx, readLogsTimeout) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go index c5bc047e8f4..282f89d370c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -315,6 +317,352 @@ func newEntry(p *logEventProvider, i int, args ...string) (LogTriggerConfig, upk return cfg, f } +func countRemainingLogs(logs map[int64][]logpoller.Log) int { + count := 0 + for _, logList := range logs { + count += len(logList) + } + return count +} + +func remainingBlockWindowCounts(queues map[string]*upkeepLogQueue, blockRate int) map[int64]int { + blockWindowCounts := map[int64]int{} + + for _, q := range queues { + for blockNumber, logs := range q.logs { + start, _ := getBlockWindow(blockNumber, blockRate) + + blockWindowCounts[start] += len(logs) + } + } + + return blockWindowCounts +} + +func TestLogEventProvider_GetLatestPayloads(t *testing.T) { + t.Run("dequeuing from an empty buffer returns 0 logs", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 100, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 0, len(payloads)) + }) + + t.Run("a single log for a single upkeep gets dequeued", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 100, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1 + + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 1, len(payloads)) + }) + + t.Run("a log per upkeep for 4 upkeeps across 4 blocks (2 separate block windows) is dequeued, for a total of 4 payloads", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 100, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1 + + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}) + buffer.Enqueue(big.NewInt(2), logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x2"), LogIndex: 0}) + buffer.Enqueue(big.NewInt(3), logpoller.Log{BlockNumber: 3, TxHash: common.HexToHash("0x3"), LogIndex: 0}) + buffer.Enqueue(big.NewInt(4), logpoller.Log{BlockNumber: 4, TxHash: common.HexToHash("0x4"), LogIndex: 0}) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 4, len(payloads)) + }) + + t.Run("100 logs are dequeued for a single upkeep, 1 log for every block window across 100 blocks followed by best effort", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 101, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1.(*logBuffer) + + for i := 0; i < 100; i++ { + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x%d", i+1)), LogIndex: 0}) + } + + assert.Equal(t, 100, countRemainingLogs(buffer.queues["1"].logs)) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + assert.Equal(t, 0, countRemainingLogs(buffer.queues["1"].logs)) + }) + + t.Run("100 logs are dequeued for two upkeeps, 25 logs each as min commitment (50 logs total best effort), followed by best effort", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 101, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1.(*logBuffer) + + for i := 0; i < 100; i++ { + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x1%d", i+1)), LogIndex: 0}) + buffer.Enqueue(big.NewInt(2), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x2%d", i+1)), LogIndex: 0}) + } + + assert.Equal(t, 100, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 100, countRemainingLogs(buffer.queues["2"].logs)) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + assert.Equal(t, 50, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 50, countRemainingLogs(buffer.queues["2"].logs)) + + windowCount := remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 2, windowCount[0]) + assert.Equal(t, 4, windowCount[48]) + assert.Equal(t, 4, windowCount[96]) + + // the second dequeue call will retrieve the remaining 100 logs and exhaust the queues + payloads, err = provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + assert.Equal(t, 0, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 0, countRemainingLogs(buffer.queues["2"].logs)) + + windowCount = remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 0, windowCount[0]) + assert.Equal(t, 0, windowCount[48]) + assert.Equal(t, 0, windowCount[96]) + }) + + t.Run("minimum guaranteed for all windows including an incomplete window followed by best effort", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 102, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1.(*logBuffer) + + for i := 0; i < 102; i++ { + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x1%d", i+1)), LogIndex: 0}) + buffer.Enqueue(big.NewInt(2), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x2%d", i+1)), LogIndex: 0}) + } + + assert.Equal(t, 102, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 102, countRemainingLogs(buffer.queues["2"].logs)) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + windowCount := remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 6, windowCount[100]) + + payloads, err = provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + // upkeep 1 has had the minimum number of logs dequeued on the latest (incomplete) window + assert.Equal(t, 1, buffer.queues["1"].dequeued[100]) + // upkeep 2 has had the minimum number of logs dequeued on the latest (incomplete) window + assert.Equal(t, 1, buffer.queues["2"].dequeued[100]) + + // the third dequeue call will retrieve the remaining 100 logs and exhaust the queues + payloads, err = provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 4, len(payloads)) + + assert.Equal(t, 0, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 0, countRemainingLogs(buffer.queues["2"].logs)) + + windowCount = remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 0, windowCount[0]) + assert.Equal(t, 0, windowCount[28]) + assert.Equal(t, 0, windowCount[32]) + assert.Equal(t, 0, windowCount[36]) + assert.Equal(t, 0, windowCount[48]) + assert.Equal(t, 0, windowCount[96]) + assert.Equal(t, 0, windowCount[100]) + }) + + t.Run("min dequeue followed by best effort followed by reorg followed by best effort", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 101, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1.(*logBuffer) + + for i := 0; i < 100; i++ { + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x1%d", i+1)), LogIndex: 0}) + buffer.Enqueue(big.NewInt(2), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x2%d", i+1)), LogIndex: 0}) + } + + assert.Equal(t, 100, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 100, countRemainingLogs(buffer.queues["2"].logs)) + + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + windowCount := remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 4, windowCount[28]) + + // reorg block 28 + buffer.Enqueue(big.NewInt(1), logpoller.Log{BlockNumber: int64(28), TxHash: common.HexToHash(fmt.Sprintf("0xreorg1%d", 28)), LogIndex: 0, BlockHash: common.BytesToHash([]byte("reorg"))}) + buffer.Enqueue(big.NewInt(2), logpoller.Log{BlockNumber: int64(28), TxHash: common.HexToHash(fmt.Sprintf("0xreorg2%d", 28)), LogIndex: 0, BlockHash: common.BytesToHash([]byte("reorg"))}) + + windowCount = remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 6, windowCount[28]) + + // the second dequeue call will retrieve the remaining 100 logs and exhaust the queues + payloads, err = provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + windowCount = remainingBlockWindowCounts(buffer.queues, 4) + + assert.Equal(t, 0, windowCount[0]) + assert.Equal(t, 0, windowCount[28]) + assert.Equal(t, 0, windowCount[32]) + assert.Equal(t, 0, windowCount[36]) + assert.Equal(t, 0, windowCount[48]) + assert.Equal(t, 2, windowCount[96]) // these 2 remaining logs are because of the 2 re orgd logs taking up dequeue space + }) + + t.Run("sparsely populated blocks", func(t *testing.T) { + opts := NewOptions(200, big.NewInt(42161)) + opts.BufferVersion = "v1" + + logPoller := &mockLogPoller{ + LatestBlockFn: func(ctx context.Context) (int64, error) { + return 100, nil + }, + } + + provider := NewLogProvider(logger.TestLogger(t), logPoller, big.NewInt(42161), &mockedPacker{}, nil, opts) + + ctx := context.Background() + + buffer := provider.bufferV1.(*logBuffer) + + upkeepOmittedOnBlocks := map[int64][]int{ + 1: {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, // upkeep 1 won't have logs on 20 blocks + 2: {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100}, // upkeep 2 won't have logs on 50 blocks + 3: {3, 13, 23, 33, 43, 53, 63, 73, 83, 93}, // upkeep 3 won't appear on 10 blocks + 4: {1, 25, 50, 75, 100}, // upkeep 4 won't appear on 5 blocks + 5: {}, // upkeep 5 appears on all blocks + } + + for upkeep, skipBlocks := range upkeepOmittedOnBlocks { + blockLoop: + for i := 0; i < 100; i++ { + for _, block := range skipBlocks { + if block == i+1 { + continue blockLoop + } + } + buffer.Enqueue(big.NewInt(upkeep), logpoller.Log{BlockNumber: int64(i + 1), TxHash: common.HexToHash(fmt.Sprintf("0x1%d", i+1)), LogIndex: 0}) + } + } + + assert.Equal(t, 80, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 50, countRemainingLogs(buffer.queues["2"].logs)) + assert.Equal(t, 90, countRemainingLogs(buffer.queues["3"].logs)) + assert.Equal(t, 95, countRemainingLogs(buffer.queues["4"].logs)) + assert.Equal(t, 100, countRemainingLogs(buffer.queues["5"].logs)) + + // perform two dequeues + payloads, err := provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + payloads, err = provider.GetLatestPayloads(ctx) + assert.NoError(t, err) + assert.Equal(t, 100, len(payloads)) + + assert.Equal(t, 40, countRemainingLogs(buffer.queues["1"].logs)) + assert.Equal(t, 10, countRemainingLogs(buffer.queues["2"].logs)) + assert.Equal(t, 50, countRemainingLogs(buffer.queues["3"].logs)) + assert.Equal(t, 55, countRemainingLogs(buffer.queues["4"].logs)) + assert.Equal(t, 60, countRemainingLogs(buffer.queues["5"].logs)) + }) +} + type mockedPacker struct { } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go index f00459dee67..9e41008ed83 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go @@ -149,14 +149,14 @@ func (r *logRecoverer) Start(ctx context.Context) error { }) r.threadCtrl.Go(func(ctx context.Context) { - cleanupTicker := time.NewTicker(utils.WithJitter(GCInterval)) + cleanupTicker := services.NewTicker(GCInterval) defer cleanupTicker.Stop() for { select { case <-cleanupTicker.C: r.clean(ctx) - cleanupTicker.Reset(utils.WithJitter(GCInterval)) + cleanupTicker.Reset() case <-ctx.Done(): return } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go index ab8e9f04940..f05cc8f75f2 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go index c68e7094cca..240e4a7daa5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks 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 f14c9865c35..6927f5ba4ca 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 @@ -233,17 +233,22 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U indices[len(checkReqs)] = i results[i] = encoding.GetIneligibleCheckResultWithoutPerformData(p, encoding.UpkeepFailureReasonNone, encoding.NoPipelineError, false) + args := []interface{}{ + map[string]interface{}{ + "from": zeroAddress, + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + }, + } + + if opts.BlockNumber != nil { + args = append(args, hexutil.EncodeBig(opts.BlockNumber)) + } + var result string checkReqs = append(checkReqs, rpc.BatchElem{ Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "from": zeroAddress, - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - }, - hexutil.EncodeBig(opts.BlockNumber), - }, + Args: args, Result: &result, }) @@ -334,17 +339,23 @@ func (r *EvmRegistry) simulatePerformUpkeeps(ctx context.Context, checkResults [ } opts := r.buildCallOpts(ctx, block) + + args := []interface{}{ + map[string]interface{}{ + "from": zeroAddress, + "to": r.addr.Hex(), + "data": hexutil.Bytes(payload), + }, + } + + if opts.BlockNumber != nil { + args = append(args, hexutil.EncodeBig(opts.BlockNumber)) + } + var result string performReqs = append(performReqs, rpc.BatchElem{ Method: "eth_call", - Args: []interface{}{ - map[string]interface{}{ - "from": zeroAddress, - "to": r.addr.Hex(), - "data": hexutil.Bytes(payload), - }, - hexutil.EncodeBig(opts.BlockNumber), - }, + Args: args, Result: &result, }) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go index bf7a62aad48..e6486ca56ae 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go @@ -108,7 +108,7 @@ func (u *upkeepStateStore) Start(pctx context.Context) error { u.lggr.Debug("Starting upkeep state store") u.threadCtrl.Go(func(ctx context.Context) { - ticker := time.NewTicker(utils.WithJitter(u.cleanCadence)) + ticker := services.NewTicker(u.cleanCadence) defer ticker.Stop() flushTicker := newTickerFn(utils.WithJitter(flushCadence)) @@ -120,7 +120,7 @@ func (u *upkeepStateStore) Start(pctx context.Context) error { if err := u.cleanup(ctx); err != nil { u.lggr.Errorw("unable to clean old state values", "err", err) } - ticker.Reset(utils.WithJitter(u.cleanCadence)) + ticker.Reset() case <-flushTicker.C: u.flush(ctx) flushTicker.Reset(utils.WithJitter(flushCadence)) diff --git a/core/services/ocr2/plugins/ocr2vrf/config/config.go b/core/services/ocr2/plugins/ocr2vrf/config/config.go deleted file mode 100644 index 9df02c23344..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/config/config.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" -) - -// PluginConfig contains custom arguments for the OCR2VRF plugin. -// -// The OCR2VRF plugin runs a DKG under the hood, so it will need both -// DKG and OCR2VRF configuration fields. -// -// The DKG contract address is provided in the plugin configuration, -// however the OCR2VRF contract address is provided in the OCR2 job spec -// under the 'contractID' key. -type PluginConfig struct { - // DKG configuration fields. - DKGEncryptionPublicKey string `json:"dkgEncryptionPublicKey"` - DKGSigningPublicKey string `json:"dkgSigningPublicKey"` - DKGKeyID string `json:"dkgKeyID"` - DKGContractAddress string `json:"dkgContractAddress"` - - // VRF configuration fields - VRFCoordinatorAddress string `json:"vrfCoordinatorAddress"` - LinkEthFeedAddress string `json:"linkEthFeedAddress"` -} - -// ValidatePluginConfig validates that the given OCR2VRF plugin configuration is correct. -func ValidatePluginConfig(config PluginConfig, dkgSignKs keystore.DKGSign, dkgEncryptKs keystore.DKGEncrypt) error { - err := dkgconfig.ValidatePluginConfig(dkgconfig.PluginConfig{ - EncryptionPublicKey: config.DKGEncryptionPublicKey, - SigningPublicKey: config.DKGSigningPublicKey, - KeyID: config.DKGKeyID, - }, dkgSignKs, dkgEncryptKs) - if err != nil { - return err - } - - // NOTE: a better validation would be to call a method on the on-chain contract pointed to by this - // address. - if config.DKGContractAddress == "" { - return errors.New("dkgContractAddress field must be provided") - } - - if config.VRFCoordinatorAddress == "" { - return errors.New("vrfCoordinatorAddress field must be provided") - } - - // NOTE: similar to the above. - if config.LinkEthFeedAddress == "" { - return errors.New("linkEthFieldAddress field must be provided") - } - - return nil -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go deleted file mode 100644 index f77b99b3568..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ /dev/null @@ -1,1156 +0,0 @@ -package coordinator - -import ( - "bytes" - "context" - "encoding/binary" - "encoding/json" - "fmt" - "math/big" - "sort" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "golang.org/x/exp/maps" - "google.golang.org/protobuf/proto" - - "github.com/smartcontractkit/libocr/commontypes" - ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" - - "github.com/smartcontractkit/chainlink-vrf/dkg" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - dkg_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - vrf_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" -) - -var _ ocr2vrftypes.CoordinatorInterface = &coordinator{} - -var ( - dkgABI = evmtypes.MustGetABI(dkg_wrapper.DKGMetaData.ABI) - vrfBeaconABI = evmtypes.MustGetABI(vrf_beacon.VRFBeaconMetaData.ABI) - vrfCoordinatorABI = evmtypes.MustGetABI(vrf_coordinator.VRFCoordinatorMetaData.ABI) - counterBuckets = []float64{ - 0, - 1, - 2, - 4, - 8, - 16, - 32, - 64, - 128, - 256, - 512, - 1024, - 2048, - } - timingBuckets = []float64{ - float64(1 * time.Millisecond), - float64(5 * time.Millisecond), - float64(10 * time.Millisecond), - float64(50 * time.Millisecond), - float64(100 * time.Millisecond), - float64(500 * time.Millisecond), - float64(time.Second), - float64(5 * time.Second), - float64(10 * time.Second), - float64(30 * time.Second), - } - promLabels = []string{"evmChainID", "oracleID", "configDigest"} - promBlocksToReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "ocr2vrf_coordinator_blocks_to_report", - Help: "Number of unfulfilled and in-flight blocks that fit in current report in reportBlocks", - Buckets: counterBuckets, - }, promLabels) - promCallbacksToReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "ocr2vrf_coordinator_callbacks_to_report", - Help: "Number of unfulfilled and in-flight callbacks fit in current report in reportBlocks", - Buckets: counterBuckets, - }, promLabels) - promBlocksInReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "ocr2vrf_coordinator_blocks_in_report", - Help: "Number of blocks found in reportWillBeTransmitted", - Buckets: counterBuckets, - }, promLabels) - promCallbacksInReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "ocr2vrf_coordinator_callbacks_in_report", - Help: "Number of callbacks found in reportWillBeTransmitted", - Buckets: counterBuckets, - }, promLabels) - promMethodDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "ocr2vrf_coordinator_method_time", - Help: "The amount of time elapsed for given method call", - Buckets: timingBuckets, - }, append(promLabels, "methodName")) -) - -const ( - // VRF-only events. - randomnessRequestedEvent string = "RandomnessRequested" - randomnessFulfillmentRequestedEvent string = "RandomnessFulfillmentRequested" - randomWordsFulfilledEvent string = "RandomWordsFulfilled" - newTransmissionEvent string = "NewTransmission" - outputsServedEvent string = "OutputsServed" - - // Both VRF and DKG contracts emit this, it's an OCR event. - configSetEvent = "ConfigSet" -) - -// block is used to key into a set that tracks beacon blocks. -type block struct { - blockNumber uint64 - confDelay uint32 -} - -type blockInReport struct { - block - recentBlockHeight uint64 - recentBlockHash common.Hash -} - -type callback struct { - blockNumber uint64 - requestID *big.Int -} - -type callbackInReport struct { - callback - recentBlockHeight uint64 - recentBlockHash common.Hash -} - -type coordinator struct { - lggr logger.Logger - - lp logpoller.LogPoller - topics - finalityDepth uint32 - - onchainRouter VRFBeaconCoordinator - coordinatorAddress common.Address - beaconAddress common.Address - - // We need to keep track of DKG ConfigSet events as well. - dkgAddress common.Address - - evmClient evmclient.Client - - // set of blocks that have been scheduled for transmission. - toBeTransmittedBlocks *ocrCache[blockInReport] - // set of request id's that have been scheduled for transmission. - toBeTransmittedCallbacks *ocrCache[callbackInReport] - blockhashLookback uint64 - coordinatorConfig *ocr2vrftypes.CoordinatorConfig - configDigest ocr2Types.ConfigDigest - oracleID commontypes.OracleID -} - -// New creates a new CoordinatorInterface implementor. -func New( - ctx context.Context, - lggr logger.Logger, - beaconAddress common.Address, - coordinatorAddress common.Address, - dkgAddress common.Address, - client evmclient.Client, - logPoller logpoller.LogPoller, - finalityDepth uint32, -) (ocr2vrftypes.CoordinatorInterface, error) { - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, client) - if err != nil { - return nil, errors.Wrap(err, "onchain router creation") - } - - t := newTopics() - - // Add log filters for the log poller so that it can poll and find the logs that - // we need. - err = logPoller.RegisterFilter(ctx, logpoller.Filter{ - Name: filterName(beaconAddress, coordinatorAddress, dkgAddress), - EventSigs: []common.Hash{ - t.randomnessRequestedTopic, - t.randomnessFulfillmentRequestedTopic, - t.randomWordsFulfilledTopic, - t.configSetTopic, - t.outputsServedTopic, - t.newTransmissionTopic}, Addresses: []common.Address{beaconAddress, coordinatorAddress, dkgAddress}}) - if err != nil { - return nil, err - } - - cacheEvictionWindowSeconds := int64(60) - cacheEvictionWindow := time.Duration(cacheEvictionWindowSeconds * int64(time.Second)) - lookbackBlocks := uint64(1_000) - - return &coordinator{ - onchainRouter: onchainRouter, - coordinatorAddress: coordinatorAddress, - beaconAddress: beaconAddress, - dkgAddress: dkgAddress, - lp: logPoller, - topics: t, - finalityDepth: finalityDepth, - evmClient: client, - lggr: lggr.Named("OCR2VRFCoordinator"), - toBeTransmittedBlocks: NewBlockCache[blockInReport](cacheEvictionWindow), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](cacheEvictionWindow), - blockhashLookback: mathutil.Min(256, lookbackBlocks), - // defaults - coordinatorConfig: &ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: cacheEvictionWindowSeconds, - BatchGasLimit: 5_000_000, - CoordinatorOverhead: 50_000, - BlockGasOverhead: 50_000, - CallbackOverhead: 50_000, - LookbackBlocks: lookbackBlocks, - }, - }, nil -} - -func (c *coordinator) CurrentChainHeight(ctx context.Context) (uint64, error) { - head, err := c.lp.LatestBlock(ctx) - if err != nil { - return 0, err - } - return uint64(head.BlockNumber), nil -} - -// ReportIsOnchain returns true iff a report for the given OCR epoch/round is -// present onchain. -func (c *coordinator) ReportIsOnchain( - ctx context.Context, - epoch uint32, - round uint8, - configDigest [32]byte, -) (presentOnchain bool, err error) { - now := time.Now().UTC() - defer c.logAndEmitFunctionDuration("ReportIsOnchain", now) - - // Check if a NewTransmission event was emitted on-chain with the - // provided epoch and round. - - epochAndRound := toEpochAndRoundUint40(epoch, round) - - // this is technically NOT a hash in the regular meaning, - // however it has the same size as a common.Hash. We need - // to left-pad by bytes because it has to be 256 (or 32 bytes) - // long in order to use as a topic filter. - enrTopic := common.BytesToHash(common.LeftPadBytes(epochAndRound.Bytes(), 32)) - - c.lggr.Info(fmt.Sprintf("epoch and round: %s %s", epochAndRound.String(), enrTopic.String())) - logs, err := c.lp.IndexedLogs( - ctx, - c.topics.newTransmissionTopic, - c.beaconAddress, - 2, - []common.Hash{ - enrTopic, - }, - 1) - if err != nil { - return false, errors.Wrap(err, "log poller IndexedLogs") - } - - // Filter for valid logs that match the current config digest. - var logsWithCorrectConfigDigest []logpoller.Log - for i := 0; i < len(logs); i++ { - rawLog := toGethLog(logs[i]) - unpacked, err := c.onchainRouter.ParseLog(rawLog) - if err != nil { - c.lggr.Warnw("Incorrect log found in NewTransmissions", "log", logs[i], "err", err) - continue - } - nt, ok := unpacked.(*vrf_beacon.VRFBeaconNewTransmission) - if !ok { - c.lggr.Warnw("Type error for log in NewTransmissisons", "log", logs[i], "err", err) - continue - } - if nt.ConfigDigest == configDigest { - logsWithCorrectConfigDigest = append(logsWithCorrectConfigDigest, logs[i]) - } - } - - c.lggr.Info(fmt.Sprintf("NewTransmission logs: %+v", logsWithCorrectConfigDigest)) - - return len(logsWithCorrectConfigDigest) >= 1, nil -} - -// ReportBlocks returns the heights and hashes of the blocks which require VRF -// proofs in the current report, and the callback requests which should be -// served as part of processing that report. Everything returned by this -// should concern blocks older than the corresponding confirmationDelay. -// Blocks and callbacks it has returned previously may be returned again, as -// long as retransmissionDelay blocks have passed since they were last -// returned. The callbacks returned do not have to correspond to the blocks. -// -// The implementor is responsible for only returning well-funded callback -// requests, and blocks for which clients have actually requested random output -// -// This can be implemented on ethereum using the RandomnessRequested and -// RandomnessFulfillmentRequested events, to identify which blocks and -// callbacks need to be served, along with the NewTransmission and -// RandomWordsFulfilled events, to identify which have already been served. -func (c *coordinator) ReportBlocks( - ctx context.Context, - slotInterval uint16, // TODO: unused for now - confirmationDelays map[uint32]struct{}, - retransmissionDelay time.Duration, // TODO: unused for now - maxBlocks, // TODO: unused for now - maxCallbacks int, // TODO: unused for now -) ( - blocks []ocr2vrftypes.Block, - callbacks []ocr2vrftypes.AbstractCostedCallbackRequest, - recentBlockHashesStartHeight uint64, - recentBlockHashes []common.Hash, - err error, -) { - now := time.Now().UTC() - defer c.logAndEmitFunctionDuration("ReportBlocks", now) - - // Instantiate the gas used by this batch. - currentBatchGasLimit := c.coordinatorConfig.CoordinatorOverhead - - // TODO: use head broadcaster instead? - currentHeight, err := c.CurrentChainHeight(ctx) - if err != nil { - err = errors.Wrap(err, "header by number") - return - } - - // Evict expired items from the cache. - c.toBeTransmittedBlocks.EvictExpiredItems(now) - c.toBeTransmittedCallbacks.EvictExpiredItems(now) - - c.lggr.Infow("current chain height", "currentHeight", currentHeight) - - logs, err := c.lp.LogsWithSigs( - ctx, - int64(currentHeight-c.coordinatorConfig.LookbackBlocks), - int64(currentHeight), - []common.Hash{ - c.randomnessRequestedTopic, - c.randomnessFulfillmentRequestedTopic, - c.randomWordsFulfilledTopic, - c.outputsServedTopic, - }, - c.coordinatorAddress) - if err != nil { - err = errors.Wrapf(err, "logs with topics. address: %s", c.coordinatorAddress) - return - } - - c.lggr.Tracew("logsWithSigs", "logs", logs) - - randomnessRequestedLogs, - randomnessFulfillmentRequestedLogs, - randomWordsFulfilledLogs, - outputsServedLogs, - err := c.unmarshalLogs(logs) - if err != nil { - err = errors.Wrap(err, "unmarshal logs") - return - } - - c.lggr.Tracew( - "finished unmarshalLogs", - "RandomnessRequested", randomnessRequestedLogs, - "RandomnessFulfillmentRequested", randomnessFulfillmentRequestedLogs, - "RandomWordsFulfilled", randomWordsFulfilledLogs, - "OutputsServed", outputsServedLogs, - ) - - // Get start height for recent blockhashes. - recentBlockHashesStartHeight = uint64(0) - if currentHeight >= c.blockhashLookback { - recentBlockHashesStartHeight = currentHeight - c.blockhashLookback + 1 - } - - // Get blockhashes that pertain to requested blocks. - blockhashesMapping, err := c.getBlockhashesMappingFromRequests( - ctx, - randomnessRequestedLogs, - randomnessFulfillmentRequestedLogs, - currentHeight, - recentBlockHashesStartHeight, - ) - if err != nil { - err = errors.Wrap(err, "get blockhashes in ReportBlocks") - return - } - - // TODO BELOW: Write tests for the new blockhash retrieval. - // Obtain recent blockhashes, ordered by ascending block height. - for i := recentBlockHashesStartHeight; i <= currentHeight; i++ { - recentBlockHashes = append(recentBlockHashes, blockhashesMapping[i]) - } - - blocksRequested := make(map[block]struct{}) - redeemRandomnessBlocksRequested := make(map[block]struct{}) - unfulfilled, err := c.filterEligibleRandomnessRequests(randomnessRequestedLogs, confirmationDelays, currentHeight, blockhashesMapping) - if err != nil { - err = errors.Wrap(err, "filter requests in ReportBlocks") - return - } - for _, uf := range unfulfilled { - blocksRequested[uf] = struct{}{} - redeemRandomnessBlocksRequested[uf] = struct{}{} - } - - c.lggr.Tracew("filtered eligible randomness requests", "blocks", unfulfilled) - - callbacksRequested, unfulfilled, err := c.filterEligibleCallbacks(randomnessFulfillmentRequestedLogs, confirmationDelays, currentHeight, blockhashesMapping) - if err != nil { - err = errors.Wrap(err, "filter callbacks in ReportBlocks") - return - } - for _, uf := range unfulfilled { - blocksRequested[uf] = struct{}{} - } - - c.lggr.Tracew("filtered eligible callbacks and blocks", "callbacks", callbacksRequested, "blocks", maps.Keys(blocksRequested)) - - // Remove blocks that have already received responses so that we don't - // respond to them again. - fulfilledBlocks := c.getFulfilledBlocks(outputsServedLogs) - for _, f := range fulfilledBlocks { - delete(blocksRequested, f) - delete(redeemRandomnessBlocksRequested, f) - } - - c.lggr.Tracew("got fulfilled blocks", "fulfilled", fulfilledBlocks) - - // Fill blocks slice with valid requested blocks. - blocks = []ocr2vrftypes.Block{} - for block := range blocksRequested { - if c.coordinatorConfig.BatchGasLimit-currentBatchGasLimit < c.coordinatorConfig.BlockGasOverhead { - break - } - _, redeemRandomnessRequested := redeemRandomnessBlocksRequested[block] - blocks = append(blocks, ocr2vrftypes.Block{ - Hash: blockhashesMapping[block.blockNumber], - Height: block.blockNumber, - ConfirmationDelay: block.confDelay, - ShouldStore: redeemRandomnessRequested, - }) - currentBatchGasLimit += c.coordinatorConfig.BlockGasOverhead - } - - c.lggr.Tracew("got elligible blocks", "blocks", blocks) - - // Find unfulfilled callback requests by filtering out already fulfilled callbacks. - fulfilledRequestIDs := c.getFulfilledRequestIDs(randomWordsFulfilledLogs) - callbacks = c.filterUnfulfilledCallbacks(callbacksRequested, fulfilledRequestIDs, confirmationDelays, currentHeight, currentBatchGasLimit) - c.emitReportBlocksMetrics(len(blocks), len(callbacks)) - - // Pull request IDs from elligible callbacks for logging. There should only be - // at most 100-200 elligible callbacks in a report. - var reqIDs []*big.Int - for _, c := range callbacks { - reqIDs = append(reqIDs, c.RequestID) - } - c.lggr.Debugw("reporting blocks and callbacks", "blocks", blocks, "callbacks", reqIDs) - c.lggr.Tracew("alreday fulfilled blocks and callbacks", "blocks", fulfilledBlocks, "callbacks", maps.Keys(fulfilledRequestIDs)) - - return -} - -// getBlockhashesMappingFromRequests returns the blockhashes for enqueued request blocks. -func (c *coordinator) getBlockhashesMappingFromRequests( - ctx context.Context, - randomnessRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessRequested, - randomnessFulfillmentRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested, - currentHeight uint64, - recentBlockHashesStartHeight uint64, -) (blockhashesMapping map[uint64]common.Hash, err error) { - // Get all request + callback requests into a mapping. - rawBlocksRequested := make(map[uint64]struct{}) - for _, l := range randomnessRequestedLogs { - if isBlockEligible(l.NextBeaconOutputHeight, l.ConfDelay, currentHeight) { - rawBlocksRequested[l.NextBeaconOutputHeight] = struct{}{} - - // Also get the blockhash for the most recent cached report on this block, - // if one exists. - cacheKey := getBlockCacheKey(l.NextBeaconOutputHeight, l.ConfDelay.Uint64()) - t := c.toBeTransmittedBlocks.GetItem(cacheKey) - if t != nil { - rawBlocksRequested[t.recentBlockHeight] = struct{}{} - } - } - } - for _, l := range randomnessFulfillmentRequestedLogs { - if isBlockEligible(l.NextBeaconOutputHeight, l.ConfDelay, currentHeight) { - rawBlocksRequested[l.NextBeaconOutputHeight] = struct{}{} - - // Also get the blockhash for the most recent cached report on this callback, - // if one exists. - cacheKey := getCallbackCacheKey(l.RequestID) - t := c.toBeTransmittedCallbacks.GetItem(cacheKey) - if t != nil { - rawBlocksRequested[t.recentBlockHeight] = struct{}{} - } - } - } - - // Fill a unique list of request blocks. - requestedBlockNumbers := []uint64{} - for k := range rawBlocksRequested { - requestedBlockNumbers = append(requestedBlockNumbers, k) - } - - // Get a mapping of block numbers to block hashes. - blockhashesMapping, err = c.getBlockhashesMapping(ctx, append(requestedBlockNumbers, currentHeight, recentBlockHashesStartHeight)) - if err != nil { - err = errors.Wrap(err, "get blockhashes for ReportBlocks") - } - return -} - -func (c *coordinator) getFulfilledBlocks(outputsServedLogs []*vrf_coordinator.VRFCoordinatorOutputsServed) (fulfilled []block) { - for _, r := range outputsServedLogs { - for _, o := range r.OutputsServed { - fulfilled = append(fulfilled, block{ - blockNumber: o.Height, - confDelay: uint32(o.ConfirmationDelay.Uint64()), - }) - } - } - return -} - -// getBlockhashesMapping returns the blockhashes corresponding to a slice of block numbers. -func (c *coordinator) getBlockhashesMapping( - ctx context.Context, - blockNumbers []uint64, -) (blockhashesMapping map[uint64]common.Hash, err error) { - // GetBlocks doesn't necessarily need a sorted blockNumbers array, - // but sorting it is helpful for testing. - sort.Slice(blockNumbers, func(a, b int) bool { - return blockNumbers[a] < blockNumbers[b] - }) - - heads, err := c.lp.GetBlocksRange(ctx, blockNumbers) - if err != nil { - return nil, errors.Wrap(err, "logpoller.GetBlocks") - } - - blockhashesMapping = make(map[uint64]common.Hash) - for _, head := range heads { - blockhashesMapping[uint64(head.BlockNumber)] = head.BlockHash - } - - // Ensure that every requested block received a blockhash. - for _, b := range blockNumbers { - if _, ok := blockhashesMapping[b]; !ok { - err = fmt.Errorf("could not find all heads in db: want %d got %d", len(blockNumbers), len(heads)) - return - } - } - return -} - -// getFulfilledRequestIDs returns the request IDs referenced by the given RandomWordsFulfilled logs slice. -func (c *coordinator) getFulfilledRequestIDs(randomWordsFulfilledLogs []*vrf_wrapper.VRFCoordinatorRandomWordsFulfilled) map[uint64]struct{} { - fulfilledRequestIDs := make(map[uint64]struct{}) - for _, r := range randomWordsFulfilledLogs { - for _, requestID := range r.RequestIDs { - fulfilledRequestIDs[requestID.Uint64()] = struct{}{} - } - } - return fulfilledRequestIDs -} - -// filterUnfulfilledCallbacks returns unfulfilled callback requests given the -// callback request logs and the already fulfilled callback request IDs. -func (c *coordinator) filterUnfulfilledCallbacks( - callbacksRequested []*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested, - fulfilledRequestIDs map[uint64]struct{}, - confirmationDelays map[uint32]struct{}, - currentHeight uint64, - currentBatchGasLimit int64, -) (callbacks []ocr2vrftypes.AbstractCostedCallbackRequest) { - /** - * Callback batch ordering: - * - Callbacks are first ordered by beacon output + confirmation delay (ascending), in other words - * the fulfillments at the oldest block are first in line. - * - Within the same block, fulfillments are ordered by gasAllowance (ascending), i.e the callbacks with - * the lowest gasAllowance are first in line. - * - This ordering ensures that the oldest callbacks can be picked up first, and that as many callbacks as - * possible can be fit into a batch. - * - * Example: - * Unsorted: (outputHeight: 1, gasAllowance: 200k), (outputHeight: 3, gasAllowance: 100k), (outputHeight: 1, gasAllowance: 100k) - * Sorted: (outputHeight: 1, gasAllowance: 100k), (outputHeight: 1, gasAllowance: 200k), (outputHeight: 3, gasAllowance: 100k) - * - */ - sort.Slice(callbacksRequested, func(a, b int) bool { - aHeight := callbacksRequested[a].NextBeaconOutputHeight + callbacksRequested[a].ConfDelay.Uint64() - bHeight := callbacksRequested[b].NextBeaconOutputHeight + callbacksRequested[b].ConfDelay.Uint64() - if aHeight == bHeight { - return callbacksRequested[a].GasAllowance < callbacksRequested[b].GasAllowance - } - return aHeight < bHeight - }) - - for _, r := range callbacksRequested { - // Check if there is room left in the batch. If there is no room left, the coordinator - // will keep iterating, until it either finds a callback in a subsequent output height that - // can fit into the current batch or reaches the end of the sorted callbacks slice. - if c.coordinatorConfig.BatchGasLimit-currentBatchGasLimit < (int64(r.GasAllowance) + c.coordinatorConfig.CallbackOverhead) { - continue - } - - requestID := r.RequestID - if _, ok := fulfilledRequestIDs[requestID.Uint64()]; !ok { - // The on-chain machinery will revert requests that specify an unsupported - // confirmation delay, so this is more of a sanity check than anything else. - if _, ok := confirmationDelays[uint32(r.ConfDelay.Uint64())]; !ok { - // if we can't find the conf delay in the map then just ignore this request - c.lggr.Errorw("ignoring bad request, unsupported conf delay", - "confDelay", r.ConfDelay.String(), - "supportedConfDelays", confirmationDelays) - continue - } - - // NOTE: we already check if the callback has been fulfilled in filterEligibleCallbacks, - // so we don't need to do that again here. - if isBlockEligible(r.NextBeaconOutputHeight, r.ConfDelay, currentHeight) { - callbacks = append(callbacks, ocr2vrftypes.AbstractCostedCallbackRequest{ - BeaconHeight: r.NextBeaconOutputHeight, - ConfirmationDelay: uint32(r.ConfDelay.Uint64()), - SubscriptionID: r.SubID, - Price: big.NewInt(0), // TODO: no price tracking - RequestID: requestID, - NumWords: r.NumWords, - Requester: r.Requester, - Arguments: r.Arguments, - GasAllowance: big.NewInt(int64(r.GasAllowance)), - GasPrice: r.GasPrice, - WeiPerUnitLink: r.WeiPerUnitLink, - }) - currentBatchGasLimit += int64(r.GasAllowance) - c.lggr.Debugw("Request is unfulfilled", "requestID", requestID) - } - } - } - return callbacks -} - -// filterEligibleCallbacks extracts valid callback requests from the given logs, -// based on their readiness to be fulfilled. It also returns any unfulfilled blocks -// associated with those callbacks. -func (c *coordinator) filterEligibleCallbacks( - randomnessFulfillmentRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested, - confirmationDelays map[uint32]struct{}, - currentHeight uint64, - blockhashesMapping map[uint64]common.Hash, -) (callbacks []*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested, unfulfilled []block, err error) { - for _, r := range randomnessFulfillmentRequestedLogs { - // The on-chain machinery will revert requests that specify an unsupported - // confirmation delay, so this is more of a sanity check than anything else. - if _, ok := confirmationDelays[uint32(r.ConfDelay.Uint64())]; !ok { - // if we can't find the conf delay in the map then just ignore this request - c.lggr.Errorw("ignoring bad request, unsupported conf delay", - "confDelay", r.ConfDelay.String(), - "supportedConfDelays", confirmationDelays) - continue - } - - // Check that the callback is elligible. - if isBlockEligible(r.NextBeaconOutputHeight, r.ConfDelay, currentHeight) { - cacheKey := getCallbackCacheKey(r.RequestID) - t := c.toBeTransmittedCallbacks.GetItem(cacheKey) - // If the callback is found in the cache and the recentBlockHash from the report containing the callback - // is correct, then the callback is in-flight and should not be included in the current observation. If that - // report gets re-orged, then the recentBlockHash of the report will become invalid, in which case - // the cached callback is ignored, and the callback is added to the current observation. - inflightTransmission := (t != nil) && (t.recentBlockHash == blockhashesMapping[t.recentBlockHeight]) - if inflightTransmission { - c.lggr.Debugw("Request is in-flight", "requestID", r.RequestID) - continue - } - - callbacks = append(callbacks, r) - - // We could have a callback request that was made in a different block than what we - // have possibly already received from regular requests. - unfulfilled = append(unfulfilled, block{ - blockNumber: r.NextBeaconOutputHeight, - confDelay: uint32(r.ConfDelay.Uint64()), - }) - c.lggr.Debugw("Request is eligible", "requestID", r.RequestID) - } - } - return -} - -// filterEligibleRandomnessRequests extracts valid randomness requests from the given logs, -// based on their readiness to be fulfilled. -func (c *coordinator) filterEligibleRandomnessRequests( - randomnessRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessRequested, - confirmationDelays map[uint32]struct{}, - currentHeight uint64, - blockhashesMapping map[uint64]common.Hash, -) (unfulfilled []block, err error) { - for _, r := range randomnessRequestedLogs { - // The on-chain machinery will revert requests that specify an unsupported - // confirmation delay, so this is more of a sanity check than anything else. - if _, ok := confirmationDelays[uint32(r.ConfDelay.Uint64())]; !ok { - // if we can't find the conf delay in the map then just ignore this request - c.lggr.Errorw("ignoring bad request, unsupported conf delay", - "confDelay", r.ConfDelay.String(), - "supportedConfDelays", confirmationDelays) - continue - } - - // Check that the block is elligible. - if isBlockEligible(r.NextBeaconOutputHeight, r.ConfDelay, currentHeight) { - cacheKey := getBlockCacheKey(r.NextBeaconOutputHeight, r.ConfDelay.Uint64()) - t := c.toBeTransmittedBlocks.GetItem(cacheKey) - // If the block is found in the cache and the recentBlockHash from the report containing the block - // is correct, then the block is in-flight and should not be included in the current observation. If that - // report gets re-orged, then the recentBlockHash of the report will become invalid, in which case - // the cached block is ignored and the block is added to the current observation. - validTransmission := (t != nil) && (t.recentBlockHash == blockhashesMapping[t.recentBlockHeight]) - if validTransmission { - c.lggr.Debugw("Block is in-flight", "blockNumber", r.NextBeaconOutputHeight, "confDelay", r.ConfDelay) - continue - } - - unfulfilled = append(unfulfilled, block{ - blockNumber: r.NextBeaconOutputHeight, - confDelay: uint32(r.ConfDelay.Uint64()), - }) - c.lggr.Debugw("Block is eligible", "blockNumber", r.NextBeaconOutputHeight, "confDelay", r.ConfDelay) - } - } - return -} - -func (c *coordinator) unmarshalLogs( - logs []logpoller.Log, -) ( - randomnessRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessRequested, - randomnessFulfillmentRequestedLogs []*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested, - randomWordsFulfilledLogs []*vrf_wrapper.VRFCoordinatorRandomWordsFulfilled, - outputsServedLogs []*vrf_wrapper.VRFCoordinatorOutputsServed, - err error, -) { - for _, lg := range logs { - rawLog := toGethLog(lg) - switch lg.EventSig { - case c.randomnessRequestedTopic: - unpacked, err2 := c.onchainRouter.ParseLog(rawLog) - if err2 != nil { - // should never happen - err = errors.Wrap(err2, "unmarshal RandomnessRequested log") - return - } - rr, ok := unpacked.(*vrf_wrapper.VRFCoordinatorRandomnessRequested) - if !ok { - // should never happen - err = errors.New("cast to *VRFCoordinatorRandomnessRequested") - return - } - randomnessRequestedLogs = append(randomnessRequestedLogs, rr) - case c.randomnessFulfillmentRequestedTopic: - unpacked, err2 := c.onchainRouter.ParseLog(rawLog) - if err2 != nil { - // should never happen - err = errors.Wrap(err2, "unmarshal RandomnessFulfillmentRequested log") - return - } - rfr, ok := unpacked.(*vrf_wrapper.VRFCoordinatorRandomnessFulfillmentRequested) - if !ok { - // should never happen - err = errors.New("cast to *VRFCoordinatorRandomnessFulfillmentRequested") - return - } - randomnessFulfillmentRequestedLogs = append(randomnessFulfillmentRequestedLogs, rfr) - case c.randomWordsFulfilledTopic: - unpacked, err2 := c.onchainRouter.ParseLog(rawLog) - if err2 != nil { - // should never happen - err = errors.Wrap(err2, "unmarshal RandomWordsFulfilled log") - return - } - rwf, ok := unpacked.(*vrf_wrapper.VRFCoordinatorRandomWordsFulfilled) - if !ok { - // should never happen - err = errors.New("cast to *VRFCoordinatorRandomWordsFulfilled") - return - } - randomWordsFulfilledLogs = append(randomWordsFulfilledLogs, rwf) - case c.outputsServedTopic: - unpacked, err2 := c.onchainRouter.ParseLog(rawLog) - if err2 != nil { - // should never happen - err = errors.Wrap(err2, "unmarshal OutputsServed log") - return - } - nt, ok := unpacked.(*vrf_coordinator.VRFCoordinatorOutputsServed) - if !ok { - // should never happen - err = errors.New("cast to *vrf_coordinator.VRFCoordinatorOutputsServed") - } - outputsServedLogs = append(outputsServedLogs, nt) - default: - c.lggr.Error(fmt.Sprintf("Unexpected event sig: %s", lg.EventSig)) - c.lggr.Error(fmt.Sprintf("expected one of: %s (RandomnessRequested) %s (RandomnessFulfillmentRequested) %s (RandomWordsFulfilled) %s (OutputsServed), got %s", - hexutil.Encode(c.randomnessRequestedTopic[:]), - hexutil.Encode(c.randomnessFulfillmentRequestedTopic[:]), - hexutil.Encode(c.randomWordsFulfilledTopic[:]), - hexutil.Encode(c.outputsServedTopic[:]), - lg.EventSig)) - } - } - return -} - -// ReportWillBeTransmitted registers to the CoordinatorInterface that the -// local node has accepted the AbstractReport for transmission, so that its -// blocks and callbacks can be tracked for possible later retransmission -func (c *coordinator) ReportWillBeTransmitted(ctx context.Context, report ocr2vrftypes.AbstractReport) error { - now := time.Now().UTC() - defer c.logAndEmitFunctionDuration("ReportWillBeTransmitted", now) - - // Evict expired items from the cache. - c.toBeTransmittedBlocks.EvictExpiredItems(now) - c.toBeTransmittedCallbacks.EvictExpiredItems(now) - - // Check for a re-org, and return an error if one is present. - blockhashesMapping, err := c.getBlockhashesMapping(ctx, []uint64{report.RecentBlockHeight}) - if err != nil { - return errors.Wrap(err, "getting blockhash mapping in ReportWillBeTransmitted") - } - if blockhashesMapping[report.RecentBlockHeight] != report.RecentBlockHash { - return errors.Errorf("blockhash of report does not match most recent blockhash in ReportWillBeTransmitted") - } - - blocksRequested := []blockInReport{} - callbacksRequested := []callbackInReport{} - - // Get all requested blocks and callbacks. - for _, output := range report.Outputs { - // If the VRF proof size is 0, the block is not included in this output. We still - // check for callbacks in the ouptut. - if len(output.VRFProof) > 0 { - bR := blockInReport{ - block: block{ - blockNumber: output.BlockHeight, - confDelay: output.ConfirmationDelay, - }, - recentBlockHeight: report.RecentBlockHeight, - recentBlockHash: report.RecentBlockHash, - } - // Store block in blocksRequested.br - blocksRequested = append(blocksRequested, bR) - } - - // Iterate through callbacks for output. - for _, cb := range output.Callbacks { - cbR := callbackInReport{ - callback: callback{ - blockNumber: cb.BeaconHeight, - requestID: cb.RequestID, - }, - recentBlockHeight: report.RecentBlockHeight, - recentBlockHash: report.RecentBlockHash, - } - - // Add callback to callbacksRequested. - callbacksRequested = append(callbacksRequested, cbR) - } - } - - // Apply blockhashes to blocks and mark them as transmitted. - for _, b := range blocksRequested { - cacheKey := getBlockCacheKey(b.blockNumber, uint64(b.confDelay)) - c.toBeTransmittedBlocks.CacheItem(b, cacheKey, now) - c.lggr.Debugw("Block is being transmitted", "blockNumber", b.blockNumber, "confDelay", b.confDelay) - } - - // Add the corresponding blockhashes to callbacks and mark them as transmitted. - for _, cb := range callbacksRequested { - cacheKey := getCallbackCacheKey(cb.requestID) - c.toBeTransmittedCallbacks.CacheItem(cb, cacheKey, now) - c.lggr.Debugw("Request is being transmitted", "requestID", cb.requestID) - } - - c.emitReportWillBeTransmittedMetrics(len(blocksRequested), len(callbacksRequested)) - - return nil -} - -// DKGVRFCommittees returns the addresses of the signers and transmitters -// for the DKG and VRF OCR committees. On ethereum, these can be retrieved -// from the most recent ConfigSet events for each contract. -func (c *coordinator) DKGVRFCommittees(ctx context.Context) (dkgCommittee, vrfCommittee ocr2vrftypes.OCRCommittee, err error) { - startTime := time.Now().UTC() - defer c.logAndEmitFunctionDuration("DKGVRFCommittees", startTime) - - latestVRF, err := c.lp.LatestLogByEventSigWithConfs( - ctx, - c.configSetTopic, - c.beaconAddress, - evmtypes.Confirmations(c.finalityDepth), - ) - if err != nil { - err = errors.Wrap(err, "latest vrf ConfigSet by sig with confs") - return - } - - latestDKG, err := c.lp.LatestLogByEventSigWithConfs( - ctx, - c.configSetTopic, - c.dkgAddress, - evmtypes.Confirmations(c.finalityDepth), - ) - if err != nil { - err = errors.Wrap(err, "latest dkg ConfigSet by sig with confs") - return - } - - var vrfConfigSetLog vrf_beacon.VRFBeaconConfigSet - err = vrfBeaconABI.UnpackIntoInterface(&vrfConfigSetLog, configSetEvent, latestVRF.Data) - if err != nil { - err = errors.Wrap(err, "unpack vrf ConfigSet into interface") - return - } - - var dkgConfigSetLog dkg_wrapper.DKGConfigSet - err = dkgABI.UnpackIntoInterface(&dkgConfigSetLog, configSetEvent, latestDKG.Data) - if err != nil { - err = errors.Wrap(err, "unpack dkg ConfigSet into interface") - return - } - - // len(signers) == len(transmitters), this is guaranteed by libocr. - for i := range vrfConfigSetLog.Signers { - vrfCommittee.Signers = append(vrfCommittee.Signers, vrfConfigSetLog.Signers[i]) - vrfCommittee.Transmitters = append(vrfCommittee.Transmitters, vrfConfigSetLog.Transmitters[i]) - } - - for i := range dkgConfigSetLog.Signers { - dkgCommittee.Signers = append(dkgCommittee.Signers, dkgConfigSetLog.Signers[i]) - dkgCommittee.Transmitters = append(dkgCommittee.Transmitters, dkgConfigSetLog.Transmitters[i]) - } - - return -} - -// ProvingKeyHash returns the VRF current proving block, in view of the local -// node. On ethereum this can be retrieved from the VRF contract's attribute -// s_provingKeyHash -func (c *coordinator) ProvingKeyHash(ctx context.Context) (common.Hash, error) { - h, err := c.onchainRouter.SProvingKeyHash(&bind.CallOpts{ - Context: ctx, - }) - if err != nil { - return [32]byte{}, errors.Wrap(err, "get proving block hash") - } - - return h, nil -} - -// BeaconPeriod returns the period used in the coordinator's contract -func (c *coordinator) BeaconPeriod(ctx context.Context) (uint16, error) { - beaconPeriodBlocks, err := c.onchainRouter.IBeaconPeriodBlocks(&bind.CallOpts{ - Context: ctx, - }) - if err != nil { - return 0, errors.Wrap(err, "get beacon period blocks") - } - - return uint16(beaconPeriodBlocks.Int64()), nil -} - -// ConfirmationDelays returns the list of confirmation delays defined in the coordinator's contract -func (c *coordinator) ConfirmationDelays(ctx context.Context) ([]uint32, error) { - confDelays, err := c.onchainRouter.GetConfirmationDelays(&bind.CallOpts{ - Context: ctx, - }) - if err != nil { - return nil, errors.Wrap(err, "could not get confirmation delays") - } - var result []uint32 - for _, c := range confDelays { - result = append(result, uint32(c.Uint64())) - } - return result, nil -} - -// KeyID returns the key ID from coordinator's contract -func (c *coordinator) KeyID(ctx context.Context) (dkg.KeyID, error) { - keyID, err := c.onchainRouter.SKeyID(&bind.CallOpts{Context: ctx}) - if err != nil { - return dkg.KeyID{}, errors.Wrap(err, "could not get key ID") - } - return keyID, nil -} - -// isBlockEligible returns true if and only if the nextBeaconOutputHeight plus -// the confDelay is less than the current blockchain height, meaning that the beacon -// output height has enough confirmations. -// -// NextBeaconOutputHeight is always greater than the request block, therefore -// a number of confirmations on the beacon block is always enough confirmations -// for the request block. -func isBlockEligible(nextBeaconOutputHeight uint64, confDelay *big.Int, currentHeight uint64) bool { - cond := confDelay.Uint64() < currentHeight // Edge case: for simulated chains with low block numbers - cond = cond && (nextBeaconOutputHeight+confDelay.Uint64()) < currentHeight - return cond -} - -// toEpochAndRoundUint40 returns a single unsigned 40 bit big.Int object -// that has the epoch in the first 32 bytes and the round in the last 8 bytes, -// in a big-endian fashion. -func toEpochAndRoundUint40(epoch uint32, round uint8) *big.Int { - return big.NewInt((int64(epoch) << 8) + int64(round)) -} - -func toGethLog(lg logpoller.Log) types.Log { - var topics []common.Hash - for _, b := range lg.Topics { - topics = append(topics, common.BytesToHash(b)) - } - return types.Log{ - Data: lg.Data, - Address: lg.Address, - BlockHash: lg.BlockHash, - BlockNumber: uint64(lg.BlockNumber), - Topics: topics, - TxHash: lg.TxHash, - Index: uint(lg.LogIndex), - } -} - -// getBlockCacheKey returns a cache key for a requested block -// The blockhash of the block does not need to be included in the key. Instead, -// the block cached at a given key contains a blockhash that is checked for validity -// against the log poller's current state. -func getBlockCacheKey(blockNumber uint64, confDelay uint64) common.Hash { - var blockNumberBytes [8]byte - var confDelayBytes [8]byte - - binary.BigEndian.PutUint64(blockNumberBytes[:], blockNumber) - binary.BigEndian.PutUint64(confDelayBytes[:], confDelay) - - return common.BytesToHash(bytes.Join([][]byte{blockNumberBytes[:], confDelayBytes[:]}, nil)) -} - -// getBlockCacheKey returns a cache key for a requested callback -// The blockhash of the callback does not need to be included in the key. Instead, -// the callback cached at a given key contains a blockhash that is checked for validity -// against the log poller's current state. -func getCallbackCacheKey(requestID *big.Int) common.Hash { - return common.BigToHash(requestID) -} - -// logAndEmitFunctionDuration logs the time in milliseconds and emits metrics in nanosecond for function duration -func (c *coordinator) logAndEmitFunctionDuration(funcName string, startTime time.Time) { - elapsed := time.Now().UTC().Sub(startTime) - c.lggr.Debugf("%s took %d milliseconds to complete", funcName, elapsed.Milliseconds()) - promMethodDuration.WithLabelValues( - append(c.labelValues(), funcName)..., - ).Observe(float64(elapsed.Nanoseconds())) -} - -func (c *coordinator) UpdateConfiguration( - b []byte, - configDigest ocr2Types.ConfigDigest, - oracleID commontypes.OracleID, -) error { - // Update config digest & oracle ID for epoch. - c.configDigest = configDigest - c.oracleID = oracleID - - // Unmarshal off-chain config. - err := proto.Unmarshal(b, c.coordinatorConfig) - if err != nil { - return errors.Wrap(err, "error setting offchain config on coordinator") - } - - // Update local caches with new eviction window. - cacheEvictionWindowSeconds := c.coordinatorConfig.CacheEvictionWindowSeconds - cacheEvictionWindow := time.Duration(cacheEvictionWindowSeconds * int64(time.Second)) - c.toBeTransmittedBlocks.SetEvictonWindow(cacheEvictionWindow) - c.toBeTransmittedCallbacks.SetEvictonWindow(cacheEvictionWindow) - - c.blockhashLookback = mathutil.Min(256, c.coordinatorConfig.LookbackBlocks) - c.lggr.Infow("set offchain config", - offchainConfigFields(c.coordinatorConfig)..., - ) - - return nil -} - -func offchainConfigFields(coordinatorConfig *ocr2vrftypes.CoordinatorConfig) []any { - return []any{ - "cacheEvictionWindowSeconds", coordinatorConfig.CacheEvictionWindowSeconds, - "batchGasLimit", coordinatorConfig.BatchGasLimit, - "coordinatorOverhead", coordinatorConfig.CoordinatorOverhead, - "lookbackBlocks", coordinatorConfig.LookbackBlocks, - "blockGasOverhead", coordinatorConfig.BlockGasOverhead, - "callbackOverhead", coordinatorConfig.CallbackOverhead, - } -} - -func (c *coordinator) labelValues() []string { - chainId := c.evmClient.ConfiguredChainID() - return []string{chainId.String(), fmt.Sprintf("%d", c.oracleID), common.Bytes2Hex(c.configDigest[:])} -} - -func (c *coordinator) emitReportBlocksMetrics( - numBlocks int, - numCallbacks int) { - promBlocksToReport.WithLabelValues(c.labelValues()...).Observe(float64(numBlocks)) - promCallbacksToReport.WithLabelValues(c.labelValues()...).Observe(float64(numCallbacks)) -} - -func (c *coordinator) emitReportWillBeTransmittedMetrics( - numBlocks int, - numCallbacks int) { - promBlocksInReport.WithLabelValues(c.labelValues()...).Observe(float64(numBlocks)) - promCallbacksInReport.WithLabelValues(c.labelValues()...).Observe(float64(numCallbacks)) -} - -func filterName(beaconAddress, coordinatorAddress, dkgAddress common.Address) string { - return logpoller.FilterName("VRF Coordinator", beaconAddress, coordinatorAddress, dkgAddress) -} - -func FilterNamesFromSpec(spec *job.OCR2OracleSpec) (names []string, err error) { - var cfg ocr2vrfconfig.PluginConfig - var beaconAddress, coordinatorAddress, dkgAddress evmtypes.EIP55Address - - if err = json.Unmarshal(spec.PluginConfig.Bytes(), &cfg); err != nil { - err = errors.Wrap(err, "failed to unmarshal ocr2vrf plugin config") - return nil, err - } - - if beaconAddress, err = evmtypes.NewEIP55Address(spec.ContractID); err == nil { - if coordinatorAddress, err = evmtypes.NewEIP55Address(cfg.VRFCoordinatorAddress); err == nil { - if dkgAddress, err = evmtypes.NewEIP55Address(cfg.DKGContractAddress); err == nil { - return []string{filterName(beaconAddress.Address(), coordinatorAddress.Address(), dkgAddress.Address())}, nil - } - } - } - - return nil, err -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go deleted file mode 100644 index d0f89ae4ca9..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ /dev/null @@ -1,1787 +0,0 @@ -package coordinator - -import ( - "bytes" - "crypto/rand" - "fmt" - "math/big" - "sort" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/libocr/commontypes" - ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - - "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" - - evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - lp_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" - dkg_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "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/ocr2/plugins/ocr2vrf/coordinator/mocks" -) - -func TestCoordinator_BeaconPeriod(t *testing.T) { - t.Parallel() - - t.Run("valid output", func(t *testing.T) { - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("IBeaconPeriodBlocks", mock.Anything). - Return(big.NewInt(10), nil) - c := &coordinator{ - onchainRouter: onchainRouter, - } - period, err := c.BeaconPeriod(testutils.Context(t)) - assert.NoError(t, err) - assert.Equal(t, uint16(10), period) - }) - - t.Run("invalid output", func(t *testing.T) { - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("IBeaconPeriodBlocks", mock.Anything). - Return(nil, errors.New("rpc error")) - c := &coordinator{ - onchainRouter: onchainRouter, - } - _, err := c.BeaconPeriod(testutils.Context(t)) - assert.Error(t, err) - }) -} - -func TestCoordinator_DKGVRFCommittees(t *testing.T) { - t.Parallel() - evmClient := evmclimocks.NewClient(t) - evmClient.On("ConfiguredChainID").Return(big.NewInt(1)) - - t.Run("happy path", func(t *testing.T) { - // In this test the DKG and VRF committees have the same signers and - // transmitters. This may (?) be different in practice. - - lp := lp_mocks.NewLogPoller(t) - tp := newTopics() - - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - dkgAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", mock.Anything, tp.configSetTopic, beaconAddress, evmtypes.Confirmations(10)). - Return(&logpoller.Log{ - Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), - }, nil) - lp.On("LatestLogByEventSigWithConfs", mock.Anything, tp.configSetTopic, dkgAddress, evmtypes.Confirmations(10)). - Return(&logpoller.Log{ - Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), - }, nil) - - expectedDKGVRF := ocr2vrftypes.OCRCommittee{ - Signers: []common.Address{ - common.HexToAddress("0x0A8cbEA12a06869d3EC432aB9682DAb6C761D591"), - common.HexToAddress("0xF4f9db7BB1d16b7CDfb18Ec68994c26964F59853"), - common.HexToAddress("0x22fB3F90C539457f00d8484438869135E604a655"), - common.HexToAddress("0x33CbCedccb11c9773AD78e214Ba342E979255ab3"), - common.HexToAddress("0x6ffaA96256fbC1012325cca88C79F725c33eED80"), - }, - Transmitters: []common.Address{ - common.HexToAddress("0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35"), - common.HexToAddress("0x38A6Cb196f805cC3041F6645a5A6CEC27B64430D"), - common.HexToAddress("0x47d7095CFEBF8285BdAa421Bc8268D0DB87D933C"), - common.HexToAddress("0xa8842BE973800fF61D80d2d53fa62C3a685380eB"), - common.HexToAddress("0x3750e31321aEE8c024751877070E8d5F704cE987"), - }, - } - - c := &coordinator{ - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - dkgAddress: dkgAddress, - finalityDepth: 10, - evmClient: evmClient, - } - actualDKG, actualVRF, err := c.DKGVRFCommittees(testutils.Context(t)) - assert.NoError(t, err) - assert.ElementsMatch(t, expectedDKGVRF.Signers, actualDKG.Signers) - assert.ElementsMatch(t, expectedDKGVRF.Transmitters, actualDKG.Transmitters) - assert.ElementsMatch(t, expectedDKGVRF.Signers, actualVRF.Signers) - assert.ElementsMatch(t, expectedDKGVRF.Transmitters, actualVRF.Transmitters) - }) - - t.Run("vrf log poll fails", func(t *testing.T) { - lp := lp_mocks.NewLogPoller(t) - tp := newTopics() - - beaconAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", mock.Anything, tp.configSetTopic, beaconAddress, evmtypes.Confirmations(10)). - Return(nil, errors.New("rpc error")) - - c := &coordinator{ - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - beaconAddress: beaconAddress, - finalityDepth: 10, - evmClient: evmClient, - } - - _, _, err := c.DKGVRFCommittees(testutils.Context(t)) - assert.Error(t, err) - }) - - t.Run("dkg log poll fails", func(t *testing.T) { - lp := lp_mocks.NewLogPoller(t) - tp := newTopics() - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - dkgAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", mock.Anything, tp.configSetTopic, beaconAddress, evmtypes.Confirmations(10)). - Return(&logpoller.Log{ - Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), - }, nil) - lp.On("LatestLogByEventSigWithConfs", mock.Anything, tp.configSetTopic, dkgAddress, evmtypes.Confirmations(10)). - Return(nil, errors.New("rpc error")) - - c := &coordinator{ - lp: lp, - topics: tp, - lggr: logger.TestLogger(t), - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - dkgAddress: dkgAddress, - finalityDepth: 10, - evmClient: evmClient, - } - _, _, err := c.DKGVRFCommittees(testutils.Context(t)) - assert.Error(t, err) - }) -} - -func TestCoordinator_ProvingKeyHash(t *testing.T) { - t.Parallel() - - t.Run("valid output", func(t *testing.T) { - h := crypto.Keccak256Hash([]byte("hello world")) - var expected [32]byte - copy(expected[:], h.Bytes()) - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("SProvingKeyHash", mock.Anything). - Return(expected, nil) - c := &coordinator{ - onchainRouter: onchainRouter, - } - provingKeyHash, err := c.ProvingKeyHash(testutils.Context(t)) - assert.NoError(t, err) - assert.ElementsMatch(t, expected[:], provingKeyHash[:]) - }) - - t.Run("invalid output", func(t *testing.T) { - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("SProvingKeyHash", mock.Anything). - Return([32]byte{}, errors.New("rpc error")) - c := &coordinator{ - onchainRouter: onchainRouter, - } - _, err := c.ProvingKeyHash(testutils.Context(t)) - assert.Error(t, err) - }) -} - -func TestCoordinator_ReportBlocks(t *testing.T) { - lggr := logger.TestLogger(t) - proofG1X := big.NewInt(1) - proofG1Y := big.NewInt(2) - evmClient := evmclimocks.NewClient(t) - evmClient.On("ConfiguredChainID").Return(big.NewInt(1)) - t.Run("happy path, beacon requests", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - lp := getLogPoller(t, []uint64{195}, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessRequestedLog(t, 3, 195, 192, 1, coordinatorAddress), - newRandomnessRequestedLog(t, 3, 195, 193, 2, coordinatorAddress), - }, nil).Once() - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 1) - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, callback requests", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - lp := getLogPoller(t, []uint64{195}, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 1000, coordinatorAddress), - }, nil).Once() - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 1) - for _, b := range blocks { - assert.False(t, b.ShouldStore) - } - assert.Len(t, callbacks, 3) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, beacon requests, beacon fulfillments", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - lp := getLogPoller(t, []uint64{195}, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessRequestedLog(t, 3, 195, 192, 1, coordinatorAddress), - newRandomnessRequestedLog(t, 3, 195, 193, 2, coordinatorAddress), - newOutputsServedLog(t, []vrf_coordinator.VRFBeaconTypesOutputServed{ - { - Height: 195, - ConfirmationDelay: big.NewInt(3), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - }, coordinatorAddress), - }, nil).Once() - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 0) - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, callback requests, callback fulfillments", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - lp := getLogPoller(t, []uint64{195}, latestHeadNumber, true, true, lookbackBlocks) - // Both RandomWordsFulfilled and NewTransmission events are emitted - // when a VRF fulfillment happens on chain. - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 1000, coordinatorAddress), - // Regardless of success or failure, if the fulfillment has been tried once do not report again. - newRandomWordsFulfilledLog(t, []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, []byte{1, 0, 0}, coordinatorAddress), - newOutputsServedLog(t, []vrf_coordinator.VRFBeaconTypesOutputServed{ - { - Height: 195, - ConfirmationDelay: big.NewInt(3), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - }, coordinatorAddress), - }, nil).Once() - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 0) - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, only beacon fulfillment", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - lp := getLogPoller(t, []uint64{}, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{newOutputsServedLog(t, []vrf_coordinator.VRFBeaconTypesOutputServed{ - { - Height: 195, - ConfirmationDelay: big.NewInt(3), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - }, coordinatorAddress)}, nil).Once() - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 0) - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, callback requests & callback fulfillments in-flight", func(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - - latestHeadNumber := uint64(200) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - tp := newTopics() - - lookbackBlocks := uint64(5) - // Do not include latestHeadNumber in "GetBlocksRange" call for initial "ReportWillBeTransmitted." - // Do not include recent blockhashes in range either. - lp := getLogPoller(t, []uint64{195}, latestHeadNumber, false, false /* includeLatestHeadInRange */, 0) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - report := ocr2vrftypes.AbstractReport{ - RecentBlockHeight: 195, - RecentBlockHash: common.HexToHash("0x001"), - Outputs: []ocr2vrftypes.AbstractVRFOutput{ - { - BlockHeight: 195, - ConfirmationDelay: 195, - Callbacks: []ocr2vrftypes.AbstractCostedCallbackRequest{ - { - RequestID: big.NewInt(1), - BeaconHeight: 195, - }, - { - RequestID: big.NewInt(2), - BeaconHeight: 195, - }, - { - RequestID: big.NewInt(3), - BeaconHeight: 195, - }, - }, - }, - }, - } - - err = c.ReportWillBeTransmitted(testutils.Context(t), report) - require.NoError(t, err) - - // Include latestHeadNumber in "GetBlocksRange" call for "ReportBlocks" call. - // Include recent blockhashes in range. - lp = getLogPoller(t, []uint64{195}, latestHeadNumber, true, true /* includeLatestHeadInRange */, lookbackBlocks) - c.lp = lp - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 1000, coordinatorAddress), - newOutputsServedLog(t, []vrf_coordinator.VRFBeaconTypesOutputServed{ - { - Height: 195, - ConfirmationDelay: big.NewInt(3), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - }, coordinatorAddress), - }, nil).Once() - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - assert.NoError(t, err) - assert.Len(t, blocks, 0) - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, blocks requested hits batch gas limit", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(400) - lookbackBlocks := uint64(400) - blockhashLookback := uint64(256) - - tp := newTopics() - - logs := []logpoller.Log{} - requestedBlocks := []uint64{} - - // Populate 200 request blocks. - for i := 0; i < 400; i += 2 { - logs = append(logs, newRandomnessRequestedLog(t, 1, uint64(i), 0, int64(i), coordinatorAddress)) - requestedBlocks = append(requestedBlocks, uint64(i)) - } - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, blockhashLookback) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return(logs, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: blockhashLookback, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{1: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - // Coordinator should allow 99 blocks, i.e 100 blocks - 1 block's worth of gas - // for the coordinator overhead. - assert.NoError(t, err) - assert.Len(t, blocks, 99) - for _, b := range blocks { - assert.True(t, b.ShouldStore) - } - assert.Len(t, callbacks, 0) - assert.Equal(t, latestHeadNumber-blockhashLookback+1, recentHeightStart) - assert.Len(t, recentBlocks, int(blockhashLookback)) - }) - - t.Run("happy path, last callback hits batch gas limit", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(200) - lookbackBlocks := uint64(5) - - tp := newTopics() - - requestedBlocks := []uint64{195} - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 2_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 2_900_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 1, coordinatorAddress), - }, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - // Should allow the first two callbacks, which add up to 4_950_000 + 50_000 (1 block) = 5_000_000, - // then reject the last callback for being out of gas. - assert.NoError(t, err) - assert.Len(t, blocks, 1) - for _, b := range blocks { - assert.True(t, b.ShouldStore) - } - assert.Len(t, callbacks, 2) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, sandwiched callbacks hit batch gas limit", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(200) - lookbackBlocks := uint64(5) - - tp := newTopics() - - requestedBlocks := []uint64{195} - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 10_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 10_000_000, coordinatorAddress), - }, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - // Should allow the middle callback, with an acceptable gas allowance, to be processed. - assert.NoError(t, err) - assert.Len(t, blocks, 1) - assert.Len(t, callbacks, 1) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("happy path, sandwiched callbacks with valid callback in next block hit batch gas limit", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(200) - lookbackBlocks := uint64(5) - - tp := newTopics() - - requestedBlocks := []uint64{195, 196} - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 10_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 10_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 196, 194, 4, 1000, coordinatorAddress), - }, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - // Should allow the middle callback, with an acceptable gas allowance, to be processed, - // then move to the next block and find a suitable callback. Also adds the block 196 for - // that callback. - assert.NoError(t, err) - assert.Len(t, blocks, 2) - assert.Len(t, callbacks, 2) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("correct blockhashes are retrieved with the maximum lookback", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(1000) - lookbackBlocks := uint64(256) - - tp := newTopics() - - requestedBlocks := []uint64{} - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{}, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - _, _, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - assert.NoError(t, err) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) - assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("correct blockhashes are retrieved with a capped lookback (close to genesis block)", func(t *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(100) - lookbackBlocks := uint64(100) - - tp := newTopics() - - requestedBlocks := []uint64{} - lp := getLogPoller(t, requestedBlocks, latestHeadNumber, true, true, lookbackBlocks) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{}, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - _, _, recentHeightStart, recentBlocks, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - assert.NoError(t, err) - assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) - assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) - assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) - assert.Len(t, recentBlocks, int(lookbackBlocks)) - }) - - t.Run("logpoller GetBlocks returns error", func(tt *testing.T) { - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - latestHeadNumber := uint64(200) - lookbackBlocks := uint64(5) - - tp := newTopics() - - requestedBlocks := []uint64{195, 196} - lp := lp_mocks.NewLogPoller(t) - lp.On("LatestBlock", mock.Anything). - Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) - - lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, latestHeadNumber-lookbackBlocks+1, latestHeadNumber)). - Return(nil, errors.New("GetBlocks error")) - lp.On( - "LogsWithSigs", - mock.Anything, - int64(latestHeadNumber-lookbackBlocks), - int64(latestHeadNumber), - []common.Hash{ - tp.randomnessRequestedTopic, - tp.randomnessFulfillmentRequestedTopic, - tp.randomWordsFulfilledTopic, - tp.outputsServedTopic, - }, - coordinatorAddress, - ).Return([]logpoller.Log{ - newRandomnessRequestedLog(t, 3, 195, 191, 0, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 191, 1, 10_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 192, 2, 1000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 195, 193, 3, 10_000_000, coordinatorAddress), - newRandomnessFulfillmentRequestedLog(t, 3, 196, 194, 4, 1000, coordinatorAddress), - }, nil) - - c := &coordinator{ - onchainRouter: onchainRouter, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - lp: lp, - lggr: logger.TestLogger(t), - topics: tp, - evmClient: evmClient, - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - blockhashLookback: lookbackBlocks, - } - - blocks, callbacks, _, _, err := c.ReportBlocks( - testutils.Context(t), - 0, // slotInterval: unused - map[uint32]struct{}{3: {}}, - time.Duration(0), - 100, // maxBlocks: unused - 100, // maxCallbacks: unused - ) - - assert.Error(tt, err) - assert.EqualError(tt, errors.Cause(err), "GetBlocks error") - assert.Nil(tt, blocks) - assert.Nil(tt, callbacks) - }) -} - -func TestCoordinator_ReportWillBeTransmitted(t *testing.T) { - evmClient := evmclimocks.NewClient(t) - evmClient.On("ConfiguredChainID").Return(big.NewInt(1)) - t.Run("happy path", func(t *testing.T) { - lookbackBlocks := uint64(0) - lp := getLogPoller(t, []uint64{199}, 200, false, false, 0) - c := &coordinator{ - lp: lp, - lggr: logger.TestLogger(t), - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - evmClient: evmClient, - } - assert.NoError(t, c.ReportWillBeTransmitted(testutils.Context(t), ocr2vrftypes.AbstractReport{ - RecentBlockHeight: 199, - RecentBlockHash: common.HexToHash("0x001"), - })) - }) - - t.Run("re-org", func(t *testing.T) { - lookbackBlocks := uint64(0) - lp := getLogPoller(t, []uint64{199}, 200, false, false, 0) - c := &coordinator{ - lp: lp, - lggr: logger.TestLogger(t), - toBeTransmittedBlocks: NewBlockCache[blockInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - toBeTransmittedCallbacks: NewBlockCache[callbackInReport](time.Duration(int64(lookbackBlocks) * int64(time.Second))), - coordinatorConfig: newCoordinatorConfig(lookbackBlocks), - evmClient: evmClient, - } - assert.Error(t, c.ReportWillBeTransmitted(testutils.Context(t), ocr2vrftypes.AbstractReport{ - RecentBlockHeight: 199, - RecentBlockHash: common.HexToHash("0x009"), - })) - }) -} - -func TestCoordinator_MarshalUnmarshal(t *testing.T) { - t.Parallel() - proofG1X := big.NewInt(1) - proofG1Y := big.NewInt(2) - lggr := logger.TestLogger(t) - evmClient := evmclimocks.NewClient(t) - - coordinatorAddress := newAddress(t) - beaconAddress := newAddress(t) - vrfBeaconCoordinator, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - require.NoError(t, err) - - lg := newRandomnessRequestedLog(t, 3, 1500, 1450, 1, coordinatorAddress) - rrIface, err := vrfBeaconCoordinator.ParseLog(toGethLog(lg)) - require.NoError(t, err) - rr, ok := rrIface.(*vrf_coordinator.VRFCoordinatorRandomnessRequested) - require.True(t, ok) - assert.Equal(t, uint64(1500), rr.NextBeaconOutputHeight) - assert.Equal(t, int64(3), rr.ConfDelay.Int64()) - - lg = newRandomnessFulfillmentRequestedLog(t, 3, 1500, 1450, 1, 1000, coordinatorAddress) - rfrIface, err := vrfBeaconCoordinator.ParseLog(toGethLog(lg)) - require.NoError(t, err) - rfr, ok := rfrIface.(*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested) - require.True(t, ok) - assert.Equal(t, uint64(1500), rfr.NextBeaconOutputHeight) - assert.Equal(t, int64(3), rfr.ConfDelay.Int64()) - assert.Equal(t, int64(1), rfr.RequestID.Int64()) - - configDigest := common.BigToHash(big.NewInt(10)) - lg = newNewTransmissionLog(t, beaconAddress, configDigest) - ntIface, err := vrfBeaconCoordinator.ParseLog(toGethLog(lg)) - require.NoError(t, err) - nt, ok := ntIface.(*vrf_beacon.VRFBeaconNewTransmission) - require.True(t, ok) - assert.True(t, bytes.Equal(nt.ConfigDigest[:], configDigest[:])) - assert.Equal(t, 0, nt.JuelsPerFeeCoin.Cmp(big.NewInt(1_000))) - assert.Equal(t, 0, nt.EpochAndRound.Cmp(big.NewInt(1))) - - lg = newRandomWordsFulfilledLog(t, []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, []byte{1, 1, 1}, coordinatorAddress) - rwfIface, err := vrfBeaconCoordinator.ParseLog(toGethLog(lg)) - require.NoError(t, err) - rwf, ok := rwfIface.(*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) - require.True(t, ok) - assert.Equal(t, []int64{1, 2, 3}, []int64{rwf.RequestIDs[0].Int64(), rwf.RequestIDs[1].Int64(), rwf.RequestIDs[2].Int64()}) - assert.Equal(t, []byte{1, 1, 1}, rwf.SuccessfulFulfillment) - - lg = newOutputsServedLog(t, []vrf_coordinator.VRFBeaconTypesOutputServed{ - { - Height: 1500, - ConfirmationDelay: big.NewInt(3), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - { - Height: 1505, - ConfirmationDelay: big.NewInt(4), - ProofG1X: proofG1X, - ProofG1Y: proofG1Y, - }, - }, coordinatorAddress) - - osIface, err := vrfBeaconCoordinator.ParseLog(toGethLog(lg)) - require.NoError(t, err) - os, ok := osIface.(*vrf_coordinator.VRFCoordinatorOutputsServed) - require.True(t, ok) - assert.Equal(t, uint64(1500), os.OutputsServed[0].Height) - assert.Equal(t, uint64(1505), os.OutputsServed[1].Height) - assert.Equal(t, int64(3), os.OutputsServed[0].ConfirmationDelay.Int64()) - assert.Equal(t, int64(4), os.OutputsServed[1].ConfirmationDelay.Int64()) -} - -func TestCoordinator_ReportIsOnchain(t *testing.T) { - evmClient := evmclimocks.NewClient(t) - evmClient.On("ConfiguredChainID").Return(big.NewInt(1)) - - t.Run("report is on-chain", func(t *testing.T) { - tp := newTopics() - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - lggr := logger.TestLogger(t) - - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - assert.NoError(t, err) - - epoch := uint32(20) - round := uint8(3) - epochAndRound := toEpochAndRoundUint40(epoch, round) - enrTopic := common.BytesToHash(common.LeftPadBytes(epochAndRound.Bytes(), 32)) - lp := lp_mocks.NewLogPoller(t) - configDigest := common.BigToHash(big.NewInt(1337)) - log := newNewTransmissionLog(t, beaconAddress, configDigest) - log.BlockNumber = 195 - lp.On("IndexedLogs", mock.Anything, tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ - enrTopic, - }, evmtypes.Confirmations(1)).Return([]logpoller.Log{log}, nil) - - c := &coordinator{ - lp: lp, - onchainRouter: onchainRouter, - lggr: logger.TestLogger(t), - beaconAddress: beaconAddress, - topics: tp, - evmClient: evmClient, - } - - present, err := c.ReportIsOnchain(testutils.Context(t), epoch, round, configDigest) - assert.NoError(t, err) - assert.True(t, present) - }) - - t.Run("report is on-chain for old config digest", func(t *testing.T) { - tp := newTopics() - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - lggr := logger.TestLogger(t) - - onchainRouter, err := newRouter(lggr, beaconAddress, coordinatorAddress, evmClient) - assert.NoError(t, err) - - epoch := uint32(20) - round := uint8(3) - epochAndRound := toEpochAndRoundUint40(epoch, round) - enrTopic := common.BytesToHash(common.LeftPadBytes(epochAndRound.Bytes(), 32)) - lp := lp_mocks.NewLogPoller(t) - oldConfigDigest := common.BigToHash(big.NewInt(1337)) - newConfigDigest := common.BigToHash(big.NewInt(8888)) - log := newNewTransmissionLog(t, beaconAddress, oldConfigDigest) - log.BlockNumber = 195 - lp.On("IndexedLogs", mock.Anything, tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ - enrTopic, - }, evmtypes.Confirmations(1)).Return([]logpoller.Log{log}, nil) - - c := &coordinator{ - lp: lp, - onchainRouter: onchainRouter, - lggr: logger.TestLogger(t), - beaconAddress: beaconAddress, - topics: tp, - evmClient: evmClient, - } - - present, err := c.ReportIsOnchain(testutils.Context(t), epoch, round, newConfigDigest) - assert.NoError(t, err) - assert.False(t, present) - }) - - t.Run("report is not on-chain", func(t *testing.T) { - tp := newTopics() - beaconAddress := newAddress(t) - - epoch := uint32(20) - round := uint8(3) - epochAndRound := toEpochAndRoundUint40(epoch, round) - enrTopic := common.BytesToHash(common.LeftPadBytes(epochAndRound.Bytes(), 32)) - lp := lp_mocks.NewLogPoller(t) - lp.On("IndexedLogs", mock.Anything, tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ - enrTopic, - }, evmtypes.Confirmations(1)).Return([]logpoller.Log{}, nil) - - c := &coordinator{ - lp: lp, - lggr: logger.TestLogger(t), - beaconAddress: beaconAddress, - topics: tp, - evmClient: evmClient, - } - - configDigest := common.BigToHash(big.NewInt(0)) - present, err := c.ReportIsOnchain(testutils.Context(t), epoch, round, configDigest) - assert.NoError(t, err) - assert.False(t, present) - }) -} - -func TestCoordinator_ConfirmationDelays(t *testing.T) { - t.Parallel() - - t.Run("valid output", func(t *testing.T) { - expected := [8]uint32{1, 2, 3, 4, 5, 6, 7, 8} - ret := [8]*big.Int{} - for i, delay := range expected { - ret[i] = big.NewInt(int64(delay)) - } - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("GetConfirmationDelays", mock.Anything). - Return(ret, nil) - c := &coordinator{ - onchainRouter: onchainRouter, - } - confDelays, err := c.ConfirmationDelays(testutils.Context(t)) - assert.NoError(t, err) - assert.Equal(t, expected[:], confDelays[:]) - }) - - t.Run("invalid output", func(t *testing.T) { - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("GetConfirmationDelays", mock.Anything). - Return([8]*big.Int{}, errors.New("rpc error")) - c := &coordinator{ - onchainRouter: onchainRouter, - } - _, err := c.ConfirmationDelays(testutils.Context(t)) - assert.Error(t, err) - }) -} - -func TestCoordinator_getBlockCacheKey(t *testing.T) { - t.Parallel() - - t.Run("calculates key correctly", func(t *testing.T) { - hash := getBlockCacheKey(1, 11) - assert.Equal( - t, - common.HexToHash("0x000000000000000000000000000000000000000000000001000000000000000b"), - hash, - ) - }) -} - -func TestCoordinator_KeyID(t *testing.T) { - t.Parallel() - - t.Run("valid output", func(t *testing.T) { - var keyIDBytes [32]byte - keyIDBytes[0] = 1 - expected := dkg.KeyID(keyIDBytes) - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("SKeyID", mock.Anything). - Return(keyIDBytes, nil) - c := &coordinator{ - onchainRouter: onchainRouter, - } - keyID, err := c.KeyID(testutils.Context(t)) - assert.NoError(t, err) - assert.Equal(t, expected[:], keyID[:]) - }) - - t.Run("invalid output", func(t *testing.T) { - var emptyBytes [32]byte - onchainRouter := mocks.NewVRFBeaconCoordinator(t) - onchainRouter. - On("SKeyID", mock.Anything). - Return(emptyBytes, errors.New("rpc error")) - c := &coordinator{ - onchainRouter: onchainRouter, - } - _, err := c.KeyID(testutils.Context(t)) - assert.Error(t, err) - }) -} - -func TestTopics_DKGConfigSet_VRFConfigSet(t *testing.T) { - dkgConfigSetTopic := dkg_wrapper.DKGConfigSet{}.Topic() - vrfConfigSetTopic := vrf_beacon.VRFBeaconConfigSet{}.Topic() - assert.Equal(t, dkgConfigSetTopic, vrfConfigSetTopic, "config set topics of vrf and dkg must be equal") -} - -func Test_UpdateConfiguration(t *testing.T) { - t.Parallel() - - t.Run("valid binary", func(t *testing.T) { - c := &coordinator{coordinatorConfig: newCoordinatorConfig(10), lggr: logger.TestLogger(t)} - cacheEvictionWindowSeconds := int64(60) - cacheEvictionWindow := time.Duration(cacheEvictionWindowSeconds * int64(time.Second)) - c.toBeTransmittedBlocks = NewBlockCache[blockInReport](cacheEvictionWindow) - c.toBeTransmittedCallbacks = NewBlockCache[callbackInReport](cacheEvictionWindow) - - newCoordinatorConfig := &ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: 30, - BatchGasLimit: 1_000_000, - CoordinatorOverhead: 10_000, - CallbackOverhead: 10_000, - BlockGasOverhead: 10_000, - LookbackBlocks: 1_000, - } - - require.Equal(t, cacheEvictionWindow, c.toBeTransmittedBlocks.evictionWindow) - require.Equal(t, cacheEvictionWindow, c.toBeTransmittedCallbacks.evictionWindow) - - expectedConfigDigest := ocr2Types.ConfigDigest(common.HexToHash("asd")) - expectedOracleID := commontypes.OracleID(3) - err := c.UpdateConfiguration(ocr2vrf.OffchainConfig(newCoordinatorConfig), expectedConfigDigest, expectedOracleID) - newCacheEvictionWindow := time.Duration(newCoordinatorConfig.CacheEvictionWindowSeconds * int64(time.Second)) - require.NoError(t, err) - require.Equal(t, newCoordinatorConfig.CacheEvictionWindowSeconds, c.coordinatorConfig.CacheEvictionWindowSeconds) - require.Equal(t, newCoordinatorConfig.BatchGasLimit, c.coordinatorConfig.BatchGasLimit) - require.Equal(t, newCoordinatorConfig.CoordinatorOverhead, c.coordinatorConfig.CoordinatorOverhead) - require.Equal(t, newCoordinatorConfig.CallbackOverhead, c.coordinatorConfig.CallbackOverhead) - require.Equal(t, newCoordinatorConfig.BlockGasOverhead, c.coordinatorConfig.BlockGasOverhead) - require.Equal(t, newCoordinatorConfig.LookbackBlocks, c.coordinatorConfig.LookbackBlocks) - require.Equal(t, newCacheEvictionWindow, c.toBeTransmittedBlocks.evictionWindow) - require.Equal(t, newCacheEvictionWindow, c.toBeTransmittedCallbacks.evictionWindow) - require.Equal(t, expectedConfigDigest, c.configDigest) - require.Equal(t, expectedOracleID, c.oracleID) - }) - - t.Run("invalid binary", func(t *testing.T) { - c := &coordinator{coordinatorConfig: newCoordinatorConfig(10), lggr: logger.TestLogger(t)} - - err := c.UpdateConfiguration([]byte{123}, ocr2Types.ConfigDigest{}, commontypes.OracleID(0)) - require.Error(t, err) - }) -} - -func newCoordinatorConfig(lookbackBlocks uint64) *ocr2vrftypes.CoordinatorConfig { - return &ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: 60, - BatchGasLimit: 5_000_000, - CoordinatorOverhead: 50_000, - CallbackOverhead: 50_000, - BlockGasOverhead: 50_000, - LookbackBlocks: lookbackBlocks, - } -} - -func newRandomnessRequestedLog( - t *testing.T, - confDelay int64, - nextBeaconOutputHeight uint64, - requestBlock uint64, - requestID int64, - coordinatorAddress common.Address, -) logpoller.Log { - //event RandomnessRequested( - // RequestID indexed requestID, - // address indexed requester, - // uint64 nextBeaconOutputHeight, - // ConfirmationDelay confDelay, - // uint64 subID, - // uint16 numWords - //); - e := vrf_coordinator.VRFCoordinatorRandomnessRequested{ - RequestID: big.NewInt(requestID), - Requester: common.HexToAddress("0x1234567890"), - ConfDelay: big.NewInt(confDelay), - NextBeaconOutputHeight: nextBeaconOutputHeight, - NumWords: 1, - SubID: big.NewInt(1), - CostJuels: big.NewInt(50_000), - NewSubBalance: big.NewInt(100_000), - Raw: gethtypes.Log{ - BlockNumber: requestBlock, - }, - } - var unindexed abi.Arguments - for _, a := range vrfCoordinatorABI.Events[randomnessRequestedEvent].Inputs { - if !a.Indexed { - unindexed = append(unindexed, a) - } - } - nonIndexedData, err := unindexed.Pack(e.Requester, e.NextBeaconOutputHeight, e.ConfDelay, e.SubID, e.NumWords, e.CostJuels, e.NewSubBalance) - require.NoError(t, err) - - requestIDType, err := abi.NewType("uint64", "", nil) - require.NoError(t, err) - - requestIDArg := abi.Arguments{abi.Argument{ - Name: "requestID", - Type: requestIDType, - Indexed: true, - }} - - topic1, err := requestIDArg.Pack(e.RequestID.Uint64()) - require.NoError(t, err) - - topic0 := vrfCoordinatorABI.Events[randomnessRequestedEvent].ID - lg := logpoller.Log{ - Address: coordinatorAddress, - Data: nonIndexedData, - Topics: [][]byte{ - // first topic is the event signature - topic0.Bytes(), - // second topic is requestID since it's indexed - topic1, - }, - BlockNumber: int64(requestBlock), - EventSig: topic0, - } - return lg -} - -func newRandomnessFulfillmentRequestedLog( - t *testing.T, - confDelay int64, - nextBeaconOutputHeight uint64, - requestBlock uint64, - requestID int64, - gasAllowance uint32, - coordinatorAddress common.Address, -) logpoller.Log { - //event RandomnessFulfillmentRequested( - // RequestID indexed requestID, - // address indexed requester, - // uint64 nextBeaconOutputHeight, - // ConfirmationDelay confDelay, - // uint256 subID, - // uint16 numWords, - // uint32 gasAllowance, - // uint256 gasPrice, - // uint256 weiPerUnitLink, - // bytes arguments, - // uint256 costJuels - //); - e := vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested{ - ConfDelay: big.NewInt(confDelay), - NextBeaconOutputHeight: nextBeaconOutputHeight, - RequestID: big.NewInt(1), - NumWords: 1, - GasAllowance: gasAllowance, - GasPrice: big.NewInt(0), - WeiPerUnitLink: big.NewInt(0), - SubID: big.NewInt(1), - Requester: common.HexToAddress("0x1234567890"), - CostJuels: big.NewInt(50_000), - NewSubBalance: big.NewInt(100_000), - Raw: gethtypes.Log{ - BlockNumber: requestBlock, - }, - } - var unindexed abi.Arguments - for _, a := range vrfCoordinatorABI.Events[randomnessFulfillmentRequestedEvent].Inputs { - if !a.Indexed { - unindexed = append(unindexed, a) - } - } - nonIndexedData, err := unindexed.Pack(e.Requester, e.NextBeaconOutputHeight, e.ConfDelay, e.SubID, e.NumWords, - e.GasAllowance, e.GasPrice, e.WeiPerUnitLink, e.Arguments, e.CostJuels, e.NewSubBalance) - require.NoError(t, err) - - requestIDType, err := abi.NewType("uint64", "", nil) - require.NoError(t, err) - - requestIDArg := abi.Arguments{abi.Argument{ - Name: "requestID", - Type: requestIDType, - Indexed: true, - }} - - topic0 := vrfCoordinatorABI.Events[randomnessFulfillmentRequestedEvent].ID - topic1, err := requestIDArg.Pack(e.RequestID.Uint64()) - require.NoError(t, err) - return logpoller.Log{ - Address: coordinatorAddress, - Data: nonIndexedData, - EventSig: topic0, - Topics: [][]byte{ - topic0.Bytes(), - topic1, - }, - BlockNumber: int64(requestBlock), - } -} - -func newRandomWordsFulfilledLog( - t *testing.T, - requestIDs []*big.Int, - successfulFulfillment []byte, - coordinatorAddress common.Address, -) logpoller.Log { - //event RandomWordsFulfilled( - // RequestID[] requestIDs, - // bytes successfulFulfillment, - // bytes[] truncatedErrorData - //); - e := vrf_coordinator.VRFCoordinatorRandomWordsFulfilled{ - RequestIDs: requestIDs, - SuccessfulFulfillment: successfulFulfillment, - } - packed, err := vrfCoordinatorABI.Events[randomWordsFulfilledEvent].Inputs.Pack( - e.RequestIDs, e.SuccessfulFulfillment, e.TruncatedErrorData, e.SubBalances, e.SubIDs) - require.NoError(t, err) - topic0 := vrfCoordinatorABI.Events[randomWordsFulfilledEvent].ID - return logpoller.Log{ - Address: coordinatorAddress, - Data: packed, - EventSig: topic0, - Topics: [][]byte{topic0.Bytes()}, - } -} - -func newOutputsServedLog( - t *testing.T, - outputsServed []vrf_coordinator.VRFBeaconTypesOutputServed, - beaconAddress common.Address, -) logpoller.Log { - // event OutputsServed( - // uint64 recentBlockHeight, - // address transmitter, - // uint192 juelsPerFeeCoin, - // OutputServed[] outputsServed - // ); - e := vrf_coordinator.VRFCoordinatorOutputsServed{ - RecentBlockHeight: 0, - // AggregatorRoundId: 1, - OutputsServed: outputsServed, - JuelsPerFeeCoin: big.NewInt(0), - ReasonableGasPrice: 0, - // EpochAndRound: big.NewInt(1), - // ConfigDigest: crypto.Keccak256Hash([]byte("hello world")), - } - var unindexed abi.Arguments - for _, a := range vrfCoordinatorABI.Events[outputsServedEvent].Inputs { - if !a.Indexed { - unindexed = append(unindexed, a) - } - } - nonIndexedData, err := unindexed.Pack(e.RecentBlockHeight, e.JuelsPerFeeCoin, e.ReasonableGasPrice, e.OutputsServed) - require.NoError(t, err) - - topic0 := vrfCoordinatorABI.Events[outputsServedEvent].ID - return logpoller.Log{ - Address: beaconAddress, - Data: nonIndexedData, - Topics: [][]byte{ - topic0.Bytes(), - }, - EventSig: topic0, - } -} - -func newNewTransmissionLog( - t *testing.T, - beaconAddress common.Address, - configDigest [32]byte, -) logpoller.Log { - // event NewTransmission( - // uint32 indexed aggregatorRoundId, - // uint40 indexed epochAndRound, - // address transmitter, - // uint192 juelsPerFeeCoin, - // bytes32 configDigest - // ); - e := vrf_beacon.VRFBeaconNewTransmission{ - JuelsPerFeeCoin: big.NewInt(1_000), - ReasonableGasPrice: 1_000, - EpochAndRound: big.NewInt(1), - ConfigDigest: configDigest, - Transmitter: newAddress(t), - } - var unindexed abi.Arguments - for _, a := range vrfBeaconABI.Events[newTransmissionEvent].Inputs { - if !a.Indexed { - unindexed = append(unindexed, a) - } - } - nonIndexedData, err := unindexed.Pack( - e.Transmitter, e.JuelsPerFeeCoin, e.ReasonableGasPrice, e.ConfigDigest) - require.NoError(t, err) - - // epochAndRound is indexed - epochAndRoundType, err := abi.NewType("uint40", "", nil) - require.NoError(t, err) - indexedArgs := abi.Arguments{ - { - Name: "epochAndRound", - Type: epochAndRoundType, - }, - } - epochAndRoundPacked, err := indexedArgs.Pack(e.EpochAndRound) - require.NoError(t, err) - - topic0 := vrfBeaconABI.Events[newTransmissionEvent].ID - return logpoller.Log{ - Address: beaconAddress, - Data: nonIndexedData, - Topics: [][]byte{ - topic0.Bytes(), - epochAndRoundPacked, - }, - EventSig: topic0, - } -} - -func newAddress(t *testing.T) common.Address { - b := make([]byte, 20) - _, err := rand.Read(b) - require.NoError(t, err) - return common.HexToAddress(hexutil.Encode(b)) -} - -func getLogPoller( - t *testing.T, - requestedBlocks []uint64, - latestHeadNumber uint64, - needsLatestBlock bool, - includeLatestHeadInRange bool, - blockhashLookback uint64, -) *lp_mocks.LogPoller { - lp := lp_mocks.NewLogPoller(t) - if needsLatestBlock { - lp.On("LatestBlock", mock.Anything). - Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) - } - var logPollerBlocks []logpoller.LogPollerBlock - - // If provided, ajust the blockhash range such that it starts at the most recent head. - if includeLatestHeadInRange { - requestedBlocks = append(requestedBlocks, latestHeadNumber) - } - - // If provided, adjust the blockhash range such that it includes all recent available blockhashes. - if blockhashLookback != 0 { - requestedBlocks = append(requestedBlocks, latestHeadNumber-blockhashLookback+1) - } - - // Sort the blocks to match the coordinator's calls. - sort.Slice(requestedBlocks, func(a, b int) bool { - return requestedBlocks[a] < requestedBlocks[b] - }) - - // Fill range of blocks based on requestedBlocks - // example: requestedBlocks [195, 197] -> [{BlockNumber: 195, BlockHash: 0x001}, {BlockNumber: 196, BlockHash: 0x002}, {BlockNumber: 197, BlockHash: 0x003}] - minRequestedBlock := mathutil.Min(requestedBlocks[0], requestedBlocks[1:]...) - maxRequestedBlock := mathutil.Max(requestedBlocks[0], requestedBlocks[1:]...) - for i := minRequestedBlock; i <= maxRequestedBlock; i++ { - logPollerBlocks = append(logPollerBlocks, logpoller.LogPollerBlock{ - BlockNumber: int64(i), - BlockHash: common.HexToHash(fmt.Sprintf("0x00%d", i-minRequestedBlock+1)), - }) - } - - lp.On("GetBlocksRange", mock.Anything, requestedBlocks). - Return(logPollerBlocks, nil) - - return lp -} - -func TestFilterNamesFromSpec(t *testing.T) { - beaconAddress := newAddress(t) - coordinatorAddress := newAddress(t) - dkgAddress := newAddress(t) - - spec := &job.OCR2OracleSpec{ - ContractID: beaconAddress.String(), - PluginType: types.OCR2VRF, - PluginConfig: job.JSONConfig{ - "VRFCoordinatorAddress": coordinatorAddress.String(), - "DKGContractAddress": dkgAddress.String(), - }, - } - - names, err := FilterNamesFromSpec(spec) - require.NoError(t, err) - - assert.Len(t, names, 1) - assert.Equal(t, logpoller.FilterName("VRF Coordinator", beaconAddress, coordinatorAddress, dkgAddress), names[0]) - - spec = &job.OCR2OracleSpec{ - PluginType: types.OCR2VRF, - ContractID: beaconAddress.String(), - PluginConfig: nil, // missing coordinator & dkg addresses - } - _, err = FilterNamesFromSpec(spec) - require.ErrorContains(t, err, "is not a valid EIP55 formatted address") -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/interfaces.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/interfaces.go deleted file mode 100644 index 67dd567b68d..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/interfaces.go +++ /dev/null @@ -1,31 +0,0 @@ -package coordinator - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -//go:generate mockery --quiet --name VRFBeaconCoordinator --output ./mocks/ --case=underscore - -// VRFBeaconCoordinator is an interface that defines methods needed by the off-chain coordinator -type VRFBeaconCoordinator interface { - // SProvingKeyHash retrieves the proving key hash from the on-chain contract. - SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) - - // SKeyID retrieves the keyID from the on-chain contract. - SKeyID(opts *bind.CallOpts) ([32]byte, error) - - // IBeaconPeriodBlocks retrieves the beacon period in blocks from the on-chain contract. - IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) - - // ParseLog parses the raw log data and topics into a go object. - // The returned object must be casted to the expected type. - ParseLog(log types.Log) (generated.AbigenLog, error) - - // GetConfirmationDelays retrieves confirmation delays from the on-chain contract. - GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go deleted file mode 100644 index 1aeb0ea85c4..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go +++ /dev/null @@ -1,2179 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - common "github.com/ethereum/go-ethereum/common" - - event "github.com/ethereum/go-ethereum/event" - - generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - - mock "github.com/stretchr/testify/mock" - - types "github.com/ethereum/go-ethereum/core/types" - - vrf_beacon "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" -) - -// VRFBeaconInterface is an autogenerated mock type for the VRFBeaconInterface type -type VRFBeaconInterface struct { - mock.Mock -} - -// AcceptOwnership provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for AcceptOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AcceptPayeeship provides a mock function with given fields: opts, transmitter -func (_m *VRFBeaconInterface) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, transmitter) - - if len(ret) == 0 { - panic("no return value specified for AcceptPayeeship") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, transmitter) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, transmitter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, transmitter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Address provides a mock function with given fields: -func (_m *VRFBeaconInterface) Address() common.Address { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Address") - } - - var r0 common.Address - if rf, ok := ret.Get(0).(func() common.Address); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - return r0 -} - -// ExposeType provides a mock function with given fields: opts, arg0 -func (_m *VRFBeaconInterface) ExposeType(opts *bind.TransactOpts, arg0 vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error) { - ret := _m.Called(opts, arg0) - - if len(ret) == 0 { - panic("no return value specified for ExposeType") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error)); ok { - return rf(opts, arg0) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.VRFBeaconReportReport) *types.Transaction); ok { - r0 = rf(opts, arg0) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, vrf_beacon.VRFBeaconReportReport) error); ok { - r1 = rf(opts, arg0) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterBillingAccessControllerSet provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) FilterBillingAccessControllerSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterBillingAccessControllerSet") - } - - var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_beacon.VRFBeaconBillingAccessControllerSetIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterBillingSet provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) FilterBillingSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterBillingSet") - } - - var r0 *vrf_beacon.VRFBeaconBillingSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_beacon.VRFBeaconBillingSetIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconBillingSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterConfigSet provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterConfigSet") - } - - var r0 *vrf_beacon.VRFBeaconConfigSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_beacon.VRFBeaconConfigSetIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconConfigSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterNewTransmission provides a mock function with given fields: opts, epochAndRound -func (_m *VRFBeaconInterface) FilterNewTransmission(opts *bind.FilterOpts, epochAndRound []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error) { - ret := _m.Called(opts, epochAndRound) - - if len(ret) == 0 { - panic("no return value specified for FilterNewTransmission") - } - - var r0 *vrf_beacon.VRFBeaconNewTransmissionIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error)); ok { - return rf(opts, epochAndRound) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_beacon.VRFBeaconNewTransmissionIterator); ok { - r0 = rf(opts, epochAndRound) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconNewTransmissionIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, epochAndRound) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOraclePaid provides a mock function with given fields: opts, transmitter, payee, linkToken -func (_m *VRFBeaconInterface) FilterOraclePaid(opts *bind.FilterOpts, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error) { - ret := _m.Called(opts, transmitter, payee, linkToken) - - if len(ret) == 0 { - panic("no return value specified for FilterOraclePaid") - } - - var r0 *vrf_beacon.VRFBeaconOraclePaidIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error)); ok { - return rf(opts, transmitter, payee, linkToken) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) *vrf_beacon.VRFBeaconOraclePaidIterator); ok { - r0 = rf(opts, transmitter, payee, linkToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOraclePaidIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, transmitter, payee, linkToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOutputsServed provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterOutputsServed") - } - - var r0 *vrf_beacon.VRFBeaconOutputsServedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_beacon.VRFBeaconOutputsServedIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOutputsServedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to -func (_m *VRFBeaconInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferRequested") - } - - var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to -func (_m *VRFBeaconInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferred") - } - - var r0 *vrf_beacon.VRFBeaconOwnershipTransferredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *vrf_beacon.VRFBeaconOwnershipTransferredIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOwnershipTransferredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterPayeeshipTransferRequested provides a mock function with given fields: opts, transmitter, current, proposed -func (_m *VRFBeaconInterface) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, current []common.Address, proposed []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error) { - ret := _m.Called(opts, transmitter, current, proposed) - - if len(ret) == 0 { - panic("no return value specified for FilterPayeeshipTransferRequested") - } - - var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error)); ok { - return rf(opts, transmitter, current, proposed) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) *vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator); ok { - r0 = rf(opts, transmitter, current, proposed) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, transmitter, current, proposed) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterPayeeshipTransferred provides a mock function with given fields: opts, transmitter, previous, current -func (_m *VRFBeaconInterface) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, previous []common.Address, current []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error) { - ret := _m.Called(opts, transmitter, previous, current) - - if len(ret) == 0 { - panic("no return value specified for FilterPayeeshipTransferred") - } - - var r0 *vrf_beacon.VRFBeaconPayeeshipTransferredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error)); ok { - return rf(opts, transmitter, previous, current) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) *vrf_beacon.VRFBeaconPayeeshipTransferredIterator); ok { - r0 = rf(opts, transmitter, previous, current) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconPayeeshipTransferredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, transmitter, previous, current) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomWordsFulfilled provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomWordsFulfilled") - } - - var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilledIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_beacon.VRFBeaconRandomWordsFulfilledIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessFulfillmentRequested provides a mock function with given fields: opts, requestID -func (_m *VRFBeaconInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error) { - ret := _m.Called(opts, requestID) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessFulfillmentRequested") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error)); ok { - return rf(opts, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator); ok { - r0 = rf(opts, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessRedeemed provides a mock function with given fields: opts, requestID, requester -func (_m *VRFBeaconInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error) { - ret := _m.Called(opts, requestID, requester) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessRedeemed") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessRedeemedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error)); ok { - return rf(opts, requestID, requester) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) *vrf_beacon.VRFBeaconRandomnessRedeemedIterator); ok { - r0 = rf(opts, requestID, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessRedeemedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, requestID, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessRequested provides a mock function with given fields: opts, requestID -func (_m *VRFBeaconInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error) { - ret := _m.Called(opts, requestID) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessRequested") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error)); ok { - return rf(opts, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_beacon.VRFBeaconRandomnessRequestedIterator); ok { - r0 = rf(opts, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetBilling provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) GetBilling(opts *bind.CallOpts) (vrf_beacon.GetBilling, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetBilling") - } - - var r0 vrf_beacon.GetBilling - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.GetBilling, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) vrf_beacon.GetBilling); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(vrf_beacon.GetBilling) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetBillingAccessController provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) GetBillingAccessController(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetBillingAccessController") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ICoordinator provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) ICoordinator(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for ICoordinator") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ILink provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) ILink(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for ILink") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// KeyGenerated provides a mock function with given fields: opts, kd -func (_m *VRFBeaconInterface) KeyGenerated(opts *bind.TransactOpts, kd vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error) { - ret := _m.Called(opts, kd) - - if len(ret) == 0 { - panic("no return value specified for KeyGenerated") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error)); ok { - return rf(opts, kd) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.KeyDataStructKeyData) *types.Transaction); ok { - r0 = rf(opts, kd) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, vrf_beacon.KeyDataStructKeyData) error); ok { - r1 = rf(opts, kd) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// LatestConfigDetails provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) LatestConfigDetails(opts *bind.CallOpts) (vrf_beacon.LatestConfigDetails, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestConfigDetails") - } - - var r0 vrf_beacon.LatestConfigDetails - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDetails, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) vrf_beacon.LatestConfigDetails); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(vrf_beacon.LatestConfigDetails) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// LatestConfigDigestAndEpoch provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestConfigDigestAndEpoch") - } - - var r0 vrf_beacon.LatestConfigDigestAndEpoch - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) vrf_beacon.LatestConfigDigestAndEpoch); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(vrf_beacon.LatestConfigDigestAndEpoch) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// LinkAvailableForPayment provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LinkAvailableForPayment") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NUMCONFDELAYS provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for NUMCONFDELAYS") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewKeyRequested provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) NewKeyRequested(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for NewKeyRequested") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// OwedPayment provides a mock function with given fields: opts, transmitterAddress -func (_m *VRFBeaconInterface) OwedPayment(opts *bind.CallOpts, transmitterAddress common.Address) (*big.Int, error) { - ret := _m.Called(opts, transmitterAddress) - - if len(ret) == 0 { - panic("no return value specified for OwedPayment") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { - return rf(opts, transmitterAddress) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok { - r0 = rf(opts, transmitterAddress) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok { - r1 = rf(opts, transmitterAddress) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Owner provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) Owner(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Owner") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseBillingAccessControllerSet provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseBillingAccessControllerSet(log types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseBillingAccessControllerSet") - } - - var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconBillingAccessControllerSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconBillingAccessControllerSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseBillingSet provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseBillingSet(log types.Log) (*vrf_beacon.VRFBeaconBillingSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseBillingSet") - } - - var r0 *vrf_beacon.VRFBeaconBillingSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconBillingSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconBillingSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseConfigSet provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseConfigSet(log types.Log) (*vrf_beacon.VRFBeaconConfigSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseConfigSet") - } - - var r0 *vrf_beacon.VRFBeaconConfigSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconConfigSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconConfigSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconConfigSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseLog provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseLog") - } - - var r0 generated.AbigenLog - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(generated.AbigenLog) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseNewTransmission provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseNewTransmission(log types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseNewTransmission") - } - - var r0 *vrf_beacon.VRFBeaconNewTransmission - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconNewTransmission); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconNewTransmission) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOraclePaid provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseOraclePaid(log types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOraclePaid") - } - - var r0 *vrf_beacon.VRFBeaconOraclePaid - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconOraclePaid); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOraclePaid) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOutputsServed provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseOutputsServed(log types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOutputsServed") - } - - var r0 *vrf_beacon.VRFBeaconOutputsServed - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconOutputsServed); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOutputsServed) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOwnershipTransferRequested provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferRequested") - } - - var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconOwnershipTransferRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOwnershipTransferRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOwnershipTransferred provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseOwnershipTransferred(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferred") - } - - var r0 *vrf_beacon.VRFBeaconOwnershipTransferred - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconOwnershipTransferred); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconOwnershipTransferred) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParsePayeeshipTransferRequested provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParsePayeeshipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParsePayeeshipTransferRequested") - } - - var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconPayeeshipTransferRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconPayeeshipTransferRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParsePayeeshipTransferred provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParsePayeeshipTransferred(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParsePayeeshipTransferred") - } - - var r0 *vrf_beacon.VRFBeaconPayeeshipTransferred - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconPayeeshipTransferred); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconPayeeshipTransferred) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomWordsFulfilled provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomWordsFulfilled") - } - - var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilled - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconRandomWordsFulfilled); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomWordsFulfilled) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessFulfillmentRequested provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessFulfillmentRequested") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessRedeemed provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessRedeemed") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessRedeemed - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconRandomnessRedeemed); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessRedeemed) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessRequested provides a mock function with given fields: log -func (_m *VRFBeaconInterface) ParseRandomnessRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessRequested") - } - - var r0 *vrf_beacon.VRFBeaconRandomnessRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_beacon.VRFBeaconRandomnessRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_beacon.VRFBeaconRandomnessRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SKeyID provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) SKeyID(opts *bind.CallOpts) ([32]byte, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SKeyID") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SKeyProvider provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) SKeyProvider(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SKeyProvider") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SProvingKeyHash provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SProvingKeyHash") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetBilling provides a mock function with given fields: opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas -func (_m *VRFBeaconInterface) SetBilling(opts *bind.TransactOpts, maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) - - if len(ret) == 0 { - panic("no return value specified for SetBilling") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, uint64, uint64, uint64, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, uint64, uint64, uint64, *big.Int) *types.Transaction); ok { - r0 = rf(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, uint64, uint64, uint64, uint64, *big.Int) error); ok { - r1 = rf(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetBillingAccessController provides a mock function with given fields: opts, _billingAccessController -func (_m *VRFBeaconInterface) SetBillingAccessController(opts *bind.TransactOpts, _billingAccessController common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, _billingAccessController) - - if len(ret) == 0 { - panic("no return value specified for SetBillingAccessController") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, _billingAccessController) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, _billingAccessController) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, _billingAccessController) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetConfig provides a mock function with given fields: opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig -func (_m *VRFBeaconInterface) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { - ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - - if len(ret) == 0 { - panic("no return value specified for SetConfig") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok { - return rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) *types.Transaction); ok { - r0 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) error); ok { - r1 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetPayees provides a mock function with given fields: opts, transmitters, payees -func (_m *VRFBeaconInterface) SetPayees(opts *bind.TransactOpts, transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, transmitters, payees) - - if len(ret) == 0 { - panic("no return value specified for SetPayees") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok { - return rf(opts, transmitters, payees) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) *types.Transaction); ok { - r0 = rf(opts, transmitters, payees) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, transmitters, payees) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TransferOwnership provides a mock function with given fields: opts, to -func (_m *VRFBeaconInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, to) - - if len(ret) == 0 { - panic("no return value specified for TransferOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, to) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TransferPayeeship provides a mock function with given fields: opts, transmitter, proposed -func (_m *VRFBeaconInterface) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, transmitter, proposed) - - if len(ret) == 0 { - panic("no return value specified for TransferPayeeship") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { - return rf(opts, transmitter, proposed) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) *types.Transaction); ok { - r0 = rf(opts, transmitter, proposed) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address) error); ok { - r1 = rf(opts, transmitter, proposed) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Transmit provides a mock function with given fields: opts, reportContext, report, rs, ss, rawVs -func (_m *VRFBeaconInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { - ret := _m.Called(opts, reportContext, report, rs, ss, rawVs) - - if len(ret) == 0 { - panic("no return value specified for Transmit") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok { - return rf(opts, reportContext, report, rs, ss, rawVs) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) *types.Transaction); ok { - r0 = rf(opts, reportContext, report, rs, ss, rawVs) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) error); ok { - r1 = rf(opts, reportContext, report, rs, ss, rawVs) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TypeAndVersion provides a mock function with given fields: opts -func (_m *VRFBeaconInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for TypeAndVersion") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchBillingAccessControllerSet provides a mock function with given fields: opts, sink -func (_m *VRFBeaconInterface) WatchBillingAccessControllerSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchBillingAccessControllerSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchBillingSet provides a mock function with given fields: opts, sink -func (_m *VRFBeaconInterface) WatchBillingSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchBillingSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingSet) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingSet) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchConfigSet provides a mock function with given fields: opts, sink -func (_m *VRFBeaconInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchConfigSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconConfigSet) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconConfigSet) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchNewTransmission provides a mock function with given fields: opts, sink, epochAndRound -func (_m *VRFBeaconInterface) WatchNewTransmission(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconNewTransmission, epochAndRound []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, epochAndRound) - - if len(ret) == 0 { - panic("no return value specified for WatchNewTransmission") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconNewTransmission, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, epochAndRound) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconNewTransmission, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, epochAndRound) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconNewTransmission, []*big.Int) error); ok { - r1 = rf(opts, sink, epochAndRound) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOraclePaid provides a mock function with given fields: opts, sink, transmitter, payee, linkToken -func (_m *VRFBeaconInterface) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOraclePaid, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, transmitter, payee, linkToken) - - if len(ret) == 0 { - panic("no return value specified for WatchOraclePaid") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOraclePaid, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, transmitter, payee, linkToken) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOraclePaid, []common.Address, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, transmitter, payee, linkToken) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOraclePaid, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, transmitter, payee, linkToken) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOutputsServed provides a mock function with given fields: opts, sink -func (_m *VRFBeaconInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchOutputsServed") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOutputsServed) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOutputsServed) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to -func (_m *VRFBeaconInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to -func (_m *VRFBeaconInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferred") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchPayeeshipTransferRequested provides a mock function with given fields: opts, sink, transmitter, current, proposed -func (_m *VRFBeaconInterface) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, transmitter []common.Address, current []common.Address, proposed []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, transmitter, current, proposed) - - if len(ret) == 0 { - panic("no return value specified for WatchPayeeshipTransferRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, transmitter, current, proposed) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, []common.Address, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, transmitter, current, proposed) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, transmitter, current, proposed) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchPayeeshipTransferred provides a mock function with given fields: opts, sink, transmitter, previous, current -func (_m *VRFBeaconInterface) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, transmitter []common.Address, previous []common.Address, current []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, transmitter, previous, current) - - if len(ret) == 0 { - panic("no return value specified for WatchPayeeshipTransferred") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, transmitter, previous, current) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, []common.Address, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, transmitter, previous, current) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, []common.Address, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, transmitter, previous, current) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomWordsFulfilled provides a mock function with given fields: opts, sink -func (_m *VRFBeaconInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomWordsFulfilled") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessFulfillmentRequested provides a mock function with given fields: opts, sink, requestID -func (_m *VRFBeaconInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessFulfillmentRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, []*big.Int) error); ok { - r1 = rf(opts, sink, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessRedeemed provides a mock function with given fields: opts, sink, requestID, requester -func (_m *VRFBeaconInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID, requester) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessRedeemed") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, requestID, requester) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, []*big.Int, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, requestID, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, sink, requestID, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessRequested provides a mock function with given fields: opts, sink, requestID -func (_m *VRFBeaconInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRequested, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRequested, []*big.Int) error); ok { - r1 = rf(opts, sink, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithdrawFunds provides a mock function with given fields: opts, recipient, amount -func (_m *VRFBeaconInterface) WithdrawFunds(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, recipient, amount) - - if len(ret) == 0 { - panic("no return value specified for WithdrawFunds") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, recipient, amount) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok { - r0 = rf(opts, recipient, amount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok { - r1 = rf(opts, recipient, amount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithdrawPayment provides a mock function with given fields: opts, transmitter -func (_m *VRFBeaconInterface) WithdrawPayment(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, transmitter) - - if len(ret) == 0 { - panic("no return value specified for WithdrawPayment") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, transmitter) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, transmitter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, transmitter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewVRFBeaconInterface creates a new instance of VRFBeaconInterface. 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 NewVRFBeaconInterface(t interface { - mock.TestingT - Cleanup(func()) -}) *VRFBeaconInterface { - mock := &VRFBeaconInterface{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go deleted file mode 100644 index d62a08f6a86..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go +++ /dev/null @@ -1,184 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - - generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - - mock "github.com/stretchr/testify/mock" - - types "github.com/ethereum/go-ethereum/core/types" -) - -// VRFBeaconCoordinator is an autogenerated mock type for the VRFBeaconCoordinator type -type VRFBeaconCoordinator struct { - mock.Mock -} - -// GetConfirmationDelays provides a mock function with given fields: opts -func (_m *VRFBeaconCoordinator) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetConfirmationDelays") - } - - var r0 [8]*big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [8]*big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([8]*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IBeaconPeriodBlocks provides a mock function with given fields: opts -func (_m *VRFBeaconCoordinator) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for IBeaconPeriodBlocks") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseLog provides a mock function with given fields: log -func (_m *VRFBeaconCoordinator) ParseLog(log types.Log) (generated.AbigenLog, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseLog") - } - - var r0 generated.AbigenLog - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(generated.AbigenLog) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SKeyID provides a mock function with given fields: opts -func (_m *VRFBeaconCoordinator) SKeyID(opts *bind.CallOpts) ([32]byte, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SKeyID") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SProvingKeyHash provides a mock function with given fields: opts -func (_m *VRFBeaconCoordinator) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SProvingKeyHash") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewVRFBeaconCoordinator creates a new instance of VRFBeaconCoordinator. 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 NewVRFBeaconCoordinator(t interface { - mock.TestingT - Cleanup(func()) -}) *VRFBeaconCoordinator { - mock := &VRFBeaconCoordinator{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go deleted file mode 100644 index 268dff05237..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go +++ /dev/null @@ -1,3093 +0,0 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - common "github.com/ethereum/go-ethereum/common" - - event "github.com/ethereum/go-ethereum/event" - - generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - - mock "github.com/stretchr/testify/mock" - - types "github.com/ethereum/go-ethereum/core/types" - - vrf_coordinator "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" -) - -// VRFCoordinatorInterface is an autogenerated mock type for the VRFCoordinatorInterface type -type VRFCoordinatorInterface struct { - mock.Mock -} - -// AcceptOwnership provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for AcceptOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AcceptSubscriptionOwnerTransfer provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for AcceptSubscriptionOwnerTransfer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) *types.Transaction); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AddConsumer provides a mock function with given fields: opts, subId, consumer -func (_m *VRFCoordinatorInterface) AddConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, subId, consumer) - - if len(ret) == 0 { - panic("no return value specified for AddConsumer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { - return rf(opts, subId, consumer) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) *types.Transaction); ok { - r0 = rf(opts, subId, consumer) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, common.Address) error); ok { - r1 = rf(opts, subId, consumer) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Address provides a mock function with given fields: -func (_m *VRFCoordinatorInterface) Address() common.Address { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Address") - } - - var r0 common.Address - if rf, ok := ret.Get(0).(func() common.Address); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - return r0 -} - -// BatchTransferLink provides a mock function with given fields: opts, recipients, paymentsInJuels -func (_m *VRFCoordinatorInterface) BatchTransferLink(opts *bind.TransactOpts, recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, recipients, paymentsInJuels) - - if len(ret) == 0 { - panic("no return value specified for BatchTransferLink") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []*big.Int) (*types.Transaction, error)); ok { - return rf(opts, recipients, paymentsInJuels) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []*big.Int) *types.Transaction); ok { - r0 = rf(opts, recipients, paymentsInJuels) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []*big.Int) error); ok { - r1 = rf(opts, recipients, paymentsInJuels) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// CancelSubscription provides a mock function with given fields: opts, subId, to -func (_m *VRFCoordinatorInterface) CancelSubscription(opts *bind.TransactOpts, subId *big.Int, to common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, subId, to) - - if len(ret) == 0 { - panic("no return value specified for CancelSubscription") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { - return rf(opts, subId, to) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) *types.Transaction); ok { - r0 = rf(opts, subId, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, common.Address) error); ok { - r1 = rf(opts, subId, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// CreateSubscription provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for CreateSubscription") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeregisterMigratableCoordinator provides a mock function with given fields: opts, target -func (_m *VRFCoordinatorInterface) DeregisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, target) - - if len(ret) == 0 { - panic("no return value specified for DeregisterMigratableCoordinator") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, target) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, target) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, target) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterCallbackConfigSet provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterCallbackConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterCallbackConfigSet") - } - - var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterCoordinatorConfigSet provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterCoordinatorConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterCoordinatorConfigSet") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterCoordinatorDeregistered provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterCoordinatorDeregistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterCoordinatorDeregistered") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterCoordinatorRegistered provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterCoordinatorRegistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterCoordinatorRegistered") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterMigrationCompleted provides a mock function with given fields: opts, newVersion, subID -func (_m *VRFCoordinatorInterface) FilterMigrationCompleted(opts *bind.FilterOpts, newVersion []uint8, subID []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error) { - ret := _m.Called(opts, newVersion, subID) - - if len(ret) == 0 { - panic("no return value specified for FilterMigrationCompleted") - } - - var r0 *vrf_coordinator.VRFCoordinatorMigrationCompletedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint8, []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error)); ok { - return rf(opts, newVersion, subID) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint8, []*big.Int) *vrf_coordinator.VRFCoordinatorMigrationCompletedIterator); ok { - r0 = rf(opts, newVersion, subID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint8, []*big.Int) error); ok { - r1 = rf(opts, newVersion, subID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOutputsServed provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterOutputsServed") - } - - var r0 *vrf_coordinator.VRFCoordinatorOutputsServedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorOutputsServedIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOutputsServedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to -func (_m *VRFCoordinatorInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to -func (_m *VRFCoordinatorInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferred") - } - - var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterPauseFlagChanged provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterPauseFlagChanged(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterPauseFlagChanged") - } - - var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomWordsFulfilled provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomWordsFulfilled") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessFulfillmentRequested provides a mock function with given fields: opts, requestID -func (_m *VRFCoordinatorInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error) { - ret := _m.Called(opts, requestID) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessFulfillmentRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error)); ok { - return rf(opts, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator); ok { - r0 = rf(opts, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessRedeemed provides a mock function with given fields: opts, requestID, requester -func (_m *VRFCoordinatorInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error) { - ret := _m.Called(opts, requestID, requester) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessRedeemed") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error)); ok { - return rf(opts, requestID, requester) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) *vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator); ok { - r0 = rf(opts, requestID, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, requestID, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterRandomnessRequested provides a mock function with given fields: opts, requestID -func (_m *VRFCoordinatorInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error) { - ret := _m.Called(opts, requestID) - - if len(ret) == 0 { - panic("no return value specified for FilterRandomnessRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error)); ok { - return rf(opts, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator); ok { - r0 = rf(opts, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionCanceled provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionCanceled") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionConsumerAdded provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionConsumerAdded") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionConsumerRemoved provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionConsumerRemoved") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionCreated provides a mock function with given fields: opts, subId, owner -func (_m *VRFCoordinatorInterface) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []*big.Int, owner []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error) { - ret := _m.Called(opts, subId, owner) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionCreated") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error)); ok { - return rf(opts, subId, owner) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) *vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator); ok { - r0 = rf(opts, subId, owner) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, subId, owner) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionFunded provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionFunded") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionOwnerTransferRequested provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionOwnerTransferRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FilterSubscriptionOwnerTransferred provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for FilterSubscriptionOwnerTransferred") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator); ok { - r0 = rf(opts, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetCallbackMemo provides a mock function with given fields: opts, requestId -func (_m *VRFCoordinatorInterface) GetCallbackMemo(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { - ret := _m.Called(opts, requestId) - - if len(ret) == 0 { - panic("no return value specified for GetCallbackMemo") - } - - var r0 [32]byte - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok { - return rf(opts, requestId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) [32]byte); ok { - r0 = rf(opts, requestId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([32]byte) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, requestId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetConfirmationDelays provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetConfirmationDelays") - } - - var r0 [8]*big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) [8]*big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([8]*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetFee provides a mock function with given fields: opts, arg0, arg1 -func (_m *VRFCoordinatorInterface) GetFee(opts *bind.CallOpts, arg0 *big.Int, arg1 []byte) (*big.Int, error) { - ret := _m.Called(opts, arg0, arg1) - - if len(ret) == 0 { - panic("no return value specified for GetFee") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, []byte) (*big.Int, error)); ok { - return rf(opts, arg0, arg1) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, []byte) *big.Int); ok { - r0 = rf(opts, arg0, arg1) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int, []byte) error); ok { - r1 = rf(opts, arg0, arg1) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetFulfillmentFee provides a mock function with given fields: opts, arg0, callbackGasLimit, arguments, arg3 -func (_m *VRFCoordinatorInterface) GetFulfillmentFee(opts *bind.CallOpts, arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { - ret := _m.Called(opts, arg0, callbackGasLimit, arguments, arg3) - - if len(ret) == 0 { - panic("no return value specified for GetFulfillmentFee") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint32, []byte, []byte) (*big.Int, error)); ok { - return rf(opts, arg0, callbackGasLimit, arguments, arg3) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint32, []byte, []byte) *big.Int); ok { - r0 = rf(opts, arg0, callbackGasLimit, arguments, arg3) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int, uint32, []byte, []byte) error); ok { - r1 = rf(opts, arg0, callbackGasLimit, arguments, arg3) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetSubscription provides a mock function with given fields: opts, subId -func (_m *VRFCoordinatorInterface) GetSubscription(opts *bind.CallOpts, subId *big.Int) (vrf_coordinator.GetSubscription, error) { - ret := _m.Called(opts, subId) - - if len(ret) == 0 { - panic("no return value specified for GetSubscription") - } - - var r0 vrf_coordinator.GetSubscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.GetSubscription, error)); ok { - return rf(opts, subId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) vrf_coordinator.GetSubscription); ok { - r0 = rf(opts, subId) - } else { - r0 = ret.Get(0).(vrf_coordinator.GetSubscription) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetSubscriptionLinkBalance provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) GetSubscriptionLinkBalance(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetSubscriptionLinkBalance") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IBeaconPeriodBlocks provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for IBeaconPeriodBlocks") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ILink provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) ILink(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for ILink") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MAXCONSUMERS provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MAXCONSUMERS") - } - - var r0 uint16 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint16); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint16) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MAXNUMWORDS provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MAXNUMWORDS") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Migrate provides a mock function with given fields: opts, newCoordinator, encodedRequest -func (_m *VRFCoordinatorInterface) Migrate(opts *bind.TransactOpts, newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { - ret := _m.Called(opts, newCoordinator, encodedRequest) - - if len(ret) == 0 { - panic("no return value specified for Migrate") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) (*types.Transaction, error)); ok { - return rf(opts, newCoordinator, encodedRequest) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) *types.Transaction); ok { - r0 = rf(opts, newCoordinator, encodedRequest) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, []byte) error); ok { - r1 = rf(opts, newCoordinator, encodedRequest) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MigrationVersion provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) MigrationVersion(opts *bind.CallOpts) (uint8, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MigrationVersion") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NUMCONFDELAYS provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for NUMCONFDELAYS") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// OnMigration provides a mock function with given fields: opts, arg0 -func (_m *VRFCoordinatorInterface) OnMigration(opts *bind.CallOpts, arg0 []byte) error { - ret := _m.Called(opts, arg0) - - if len(ret) == 0 { - panic("no return value specified for OnMigration") - } - - var r0 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, []byte) error); ok { - r0 = rf(opts, arg0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// OnTokenTransfer provides a mock function with given fields: opts, arg0, amount, data -func (_m *VRFCoordinatorInterface) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { - ret := _m.Called(opts, arg0, amount, data) - - if len(ret) == 0 { - panic("no return value specified for OnTokenTransfer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { - return rf(opts, arg0, amount, data) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) *types.Transaction); ok { - r0 = rf(opts, arg0, amount, data) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) error); ok { - r1 = rf(opts, arg0, amount, data) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Owner provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) Owner(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Owner") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseCallbackConfigSet provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseCallbackConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseCallbackConfigSet") - } - - var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorCallbackConfigSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCallbackConfigSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseCoordinatorConfigSet provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseCoordinatorConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseCoordinatorConfigSet") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseCoordinatorDeregistered provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseCoordinatorDeregistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseCoordinatorDeregistered") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseCoordinatorRegistered provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseCoordinatorRegistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseCoordinatorRegistered") - } - - var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegistered - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorCoordinatorRegistered); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorCoordinatorRegistered) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseLog provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseLog") - } - - var r0 generated.AbigenLog - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(generated.AbigenLog) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseMigrationCompleted provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseMigrationCompleted(log types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseMigrationCompleted") - } - - var r0 *vrf_coordinator.VRFCoordinatorMigrationCompleted - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorMigrationCompleted); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorMigrationCompleted) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOutputsServed provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseOutputsServed(log types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOutputsServed") - } - - var r0 *vrf_coordinator.VRFCoordinatorOutputsServed - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorOutputsServed); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOutputsServed) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOwnershipTransferRequested provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseOwnershipTransferred provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseOwnershipTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferred") - } - - var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferred - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorOwnershipTransferred); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorOwnershipTransferred) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParsePauseFlagChanged provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParsePauseFlagChanged(log types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParsePauseFlagChanged") - } - - var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChanged - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorPauseFlagChanged); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorPauseFlagChanged) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomWordsFulfilled provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomWordsFulfilled") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessFulfillmentRequested provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessFulfillmentRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessRedeemed provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessRedeemed") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemed - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorRandomnessRedeemed); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessRedeemed) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseRandomnessRequested provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseRandomnessRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRandomnessRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorRandomnessRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorRandomnessRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionCanceled provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionCanceled") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceled - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionCanceled); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionCanceled) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionConsumerAdded provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerAdded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionConsumerAdded") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionConsumerRemoved provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerRemoved(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionConsumerRemoved") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionCreated provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionCreated(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionCreated") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionCreated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionCreated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionFunded provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionFunded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionFunded") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFunded - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionFunded); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionFunded) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionOwnerTransferRequested provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionOwnerTransferRequested") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ParseSubscriptionOwnerTransferred provides a mock function with given fields: log -func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubscriptionOwnerTransferred") - } - - var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ProcessVRFOutputs provides a mock function with given fields: opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight -func (_m *VRFCoordinatorInterface) ProcessVRFOutputs(opts *bind.TransactOpts, vrfOutputs []vrf_coordinator.VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { - ret := _m.Called(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) - - if len(ret) == 0 { - panic("no return value specified for ProcessVRFOutputs") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []vrf_coordinator.VRFBeaconTypesVRFOutput, *big.Int, uint64, uint64) (*types.Transaction, error)); ok { - return rf(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []vrf_coordinator.VRFBeaconTypesVRFOutput, *big.Int, uint64, uint64) *types.Transaction); ok { - r0 = rf(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []vrf_coordinator.VRFBeaconTypesVRFOutput, *big.Int, uint64, uint64) error); ok { - r1 = rf(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RedeemRandomness provides a mock function with given fields: opts, subID, requestID, arg2 -func (_m *VRFCoordinatorInterface) RedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { - ret := _m.Called(opts, subID, requestID, arg2) - - if len(ret) == 0 { - panic("no return value specified for RedeemRandomness") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, []byte) (*types.Transaction, error)); ok { - return rf(opts, subID, requestID, arg2) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, []byte) *types.Transaction); ok { - r0 = rf(opts, subID, requestID, arg2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, *big.Int, []byte) error); ok { - r1 = rf(opts, subID, requestID, arg2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RegisterMigratableCoordinator provides a mock function with given fields: opts, target -func (_m *VRFCoordinatorInterface) RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, target) - - if len(ret) == 0 { - panic("no return value specified for RegisterMigratableCoordinator") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, target) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, target) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, target) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RemoveConsumer provides a mock function with given fields: opts, subId, consumer -func (_m *VRFCoordinatorInterface) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, subId, consumer) - - if len(ret) == 0 { - panic("no return value specified for RemoveConsumer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { - return rf(opts, subId, consumer) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) *types.Transaction); ok { - r0 = rf(opts, subId, consumer) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, common.Address) error); ok { - r1 = rf(opts, subId, consumer) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RequestRandomness provides a mock function with given fields: opts, subID, numWords, confDelay, arg3 -func (_m *VRFCoordinatorInterface) RequestRandomness(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { - ret := _m.Called(opts, subID, numWords, confDelay, arg3) - - if len(ret) == 0 { - panic("no return value specified for RequestRandomness") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, []byte) (*types.Transaction, error)); ok { - return rf(opts, subID, numWords, confDelay, arg3) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, []byte) *types.Transaction); ok { - r0 = rf(opts, subID, numWords, confDelay, arg3) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, []byte) error); ok { - r1 = rf(opts, subID, numWords, confDelay, arg3) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RequestRandomnessFulfillment provides a mock function with given fields: opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5 -func (_m *VRFCoordinatorInterface) RequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { - ret := _m.Called(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) - - if len(ret) == 0 { - panic("no return value specified for RequestRandomnessFulfillment") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, uint32, []byte, []byte) (*types.Transaction, error)); ok { - return rf(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, uint32, []byte, []byte) *types.Transaction); ok { - r0 = rf(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, uint32, []byte, []byte) error); ok { - r1 = rf(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RequestSubscriptionOwnerTransfer provides a mock function with given fields: opts, subId, newOwner -func (_m *VRFCoordinatorInterface) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int, newOwner common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, subId, newOwner) - - if len(ret) == 0 { - panic("no return value specified for RequestSubscriptionOwnerTransfer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { - return rf(opts, subId, newOwner) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) *types.Transaction); ok { - r0 = rf(opts, subId, newOwner) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, common.Address) error); ok { - r1 = rf(opts, subId, newOwner) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SCallbackConfig provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) SCallbackConfig(opts *bind.CallOpts) (vrf_coordinator.SCallbackConfig, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SCallbackConfig") - } - - var r0 vrf_coordinator.SCallbackConfig - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCallbackConfig, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) vrf_coordinator.SCallbackConfig); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(vrf_coordinator.SCallbackConfig) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SCoordinatorConfig provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) SCoordinatorConfig(opts *bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SCoordinatorConfig") - } - - var r0 vrf_coordinator.SCoordinatorConfig - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) vrf_coordinator.SCoordinatorConfig); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(vrf_coordinator.SCoordinatorConfig) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SPendingRequests provides a mock function with given fields: opts, arg0 -func (_m *VRFCoordinatorInterface) SPendingRequests(opts *bind.CallOpts, arg0 *big.Int) (vrf_coordinator.SPendingRequests, error) { - ret := _m.Called(opts, arg0) - - if len(ret) == 0 { - panic("no return value specified for SPendingRequests") - } - - var r0 vrf_coordinator.SPendingRequests - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.SPendingRequests, error)); ok { - return rf(opts, arg0) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) vrf_coordinator.SPendingRequests); ok { - r0 = rf(opts, arg0) - } else { - r0 = ret.Get(0).(vrf_coordinator.SPendingRequests) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, arg0) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SProducer provides a mock function with given fields: opts -func (_m *VRFCoordinatorInterface) SProducer(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for SProducer") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetCallbackConfig provides a mock function with given fields: opts, config -func (_m *VRFCoordinatorInterface) SetCallbackConfig(opts *bind.TransactOpts, config vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error) { - ret := _m.Called(opts, config) - - if len(ret) == 0 { - panic("no return value specified for SetCallbackConfig") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error)); ok { - return rf(opts, config) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFCoordinatorCallbackConfig) *types.Transaction); ok { - r0 = rf(opts, config) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, vrf_coordinator.VRFCoordinatorCallbackConfig) error); ok { - r1 = rf(opts, config) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetConfirmationDelays provides a mock function with given fields: opts, confDelays -func (_m *VRFCoordinatorInterface) SetConfirmationDelays(opts *bind.TransactOpts, confDelays [8]*big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, confDelays) - - if len(ret) == 0 { - panic("no return value specified for SetConfirmationDelays") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [8]*big.Int) (*types.Transaction, error)); ok { - return rf(opts, confDelays) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [8]*big.Int) *types.Transaction); ok { - r0 = rf(opts, confDelays) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [8]*big.Int) error); ok { - r1 = rf(opts, confDelays) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetCoordinatorConfig provides a mock function with given fields: opts, coordinatorConfig -func (_m *VRFCoordinatorInterface) SetCoordinatorConfig(opts *bind.TransactOpts, coordinatorConfig vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { - ret := _m.Called(opts, coordinatorConfig) - - if len(ret) == 0 { - panic("no return value specified for SetCoordinatorConfig") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error)); ok { - return rf(opts, coordinatorConfig) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFBeaconTypesCoordinatorConfig) *types.Transaction); ok { - r0 = rf(opts, coordinatorConfig) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, vrf_coordinator.VRFBeaconTypesCoordinatorConfig) error); ok { - r1 = rf(opts, coordinatorConfig) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetPauseFlag provides a mock function with given fields: opts, pause -func (_m *VRFCoordinatorInterface) SetPauseFlag(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) { - ret := _m.Called(opts, pause) - - if len(ret) == 0 { - panic("no return value specified for SetPauseFlag") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) (*types.Transaction, error)); ok { - return rf(opts, pause) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) *types.Transaction); ok { - r0 = rf(opts, pause) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, bool) error); ok { - r1 = rf(opts, pause) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetProducer provides a mock function with given fields: opts, producer -func (_m *VRFCoordinatorInterface) SetProducer(opts *bind.TransactOpts, producer common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, producer) - - if len(ret) == 0 { - panic("no return value specified for SetProducer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, producer) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, producer) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, producer) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TransferLink provides a mock function with given fields: opts, recipient, juelsAmount -func (_m *VRFCoordinatorInterface) TransferLink(opts *bind.TransactOpts, recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, recipient, juelsAmount) - - if len(ret) == 0 { - panic("no return value specified for TransferLink") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, recipient, juelsAmount) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok { - r0 = rf(opts, recipient, juelsAmount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok { - r1 = rf(opts, recipient, juelsAmount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TransferOwnership provides a mock function with given fields: opts, to -func (_m *VRFCoordinatorInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, to) - - if len(ret) == 0 { - panic("no return value specified for TransferOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, to) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchCallbackConfigSet provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchCallbackConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchCallbackConfigSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchCoordinatorConfigSet provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchCoordinatorConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchCoordinatorConfigSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchCoordinatorDeregistered provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchCoordinatorDeregistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchCoordinatorDeregistered") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchCoordinatorRegistered provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchCoordinatorRegistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchCoordinatorRegistered") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchMigrationCompleted provides a mock function with given fields: opts, sink, newVersion, subID -func (_m *VRFCoordinatorInterface) WatchMigrationCompleted(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, newVersion []uint8, subID []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, newVersion, subID) - - if len(ret) == 0 { - panic("no return value specified for WatchMigrationCompleted") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, []uint8, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, newVersion, subID) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, []uint8, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, newVersion, subID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, []uint8, []*big.Int) error); ok { - r1 = rf(opts, sink, newVersion, subID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOutputsServed provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchOutputsServed") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to -func (_m *VRFCoordinatorInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to -func (_m *VRFCoordinatorInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferred") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchPauseFlagChanged provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchPauseFlagChanged(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchPauseFlagChanged") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomWordsFulfilled provides a mock function with given fields: opts, sink -func (_m *VRFCoordinatorInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error) { - ret := _m.Called(opts, sink) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomWordsFulfilled") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error)); ok { - return rf(opts, sink) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) event.Subscription); ok { - r0 = rf(opts, sink) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) error); ok { - r1 = rf(opts, sink) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessFulfillmentRequested provides a mock function with given fields: opts, sink, requestID -func (_m *VRFCoordinatorInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessFulfillmentRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, []*big.Int) error); ok { - r1 = rf(opts, sink, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessRedeemed provides a mock function with given fields: opts, sink, requestID, requester -func (_m *VRFCoordinatorInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID, requester) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessRedeemed") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, requestID, requester) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, []*big.Int, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, requestID, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, sink, requestID, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchRandomnessRequested provides a mock function with given fields: opts, sink, requestID -func (_m *VRFCoordinatorInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, requestID) - - if len(ret) == 0 { - panic("no return value specified for WatchRandomnessRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, requestID) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, requestID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, []*big.Int) error); ok { - r1 = rf(opts, sink, requestID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionCanceled provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionCanceled") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionConsumerAdded provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionConsumerAdded") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionConsumerRemoved provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionConsumerRemoved") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionCreated provides a mock function with given fields: opts, sink, subId, owner -func (_m *VRFCoordinatorInterface) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, subId []*big.Int, owner []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId, owner) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionCreated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, []*big.Int, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, subId, owner) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, []*big.Int, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, subId, owner) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, sink, subId, owner) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionFunded provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionFunded") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionOwnerTransferRequested provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionOwnerTransferRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WatchSubscriptionOwnerTransferred provides a mock function with given fields: opts, sink, subId -func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, subId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, subId) - - if len(ret) == 0 { - panic("no return value specified for WatchSubscriptionOwnerTransferred") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, subId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, subId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, []*big.Int) error); ok { - r1 = rf(opts, sink, subId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewVRFCoordinatorInterface creates a new instance of VRFCoordinatorInterface. 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 NewVRFCoordinatorInterface(t interface { - mock.TestingT - Cleanup(func()) -}) *VRFCoordinatorInterface { - mock := &VRFCoordinatorInterface{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache.go deleted file mode 100644 index 0dab659258e..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache.go +++ /dev/null @@ -1,121 +0,0 @@ -package coordinator - -import ( - "runtime" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" -) - -// ocrCache is a caching strucuture that allows items to be stored and then evicted -// based on an eviction window. In this package, it is being used to track in-flight -// items the coordinator includes in OCR reports, such that the items can be checked against -// the cache to avoid double-transmissions. -type ocrCache[T any] struct { - evictionWindow time.Duration - cacheMu sync.Mutex - cache map[common.Hash]*cacheItem[T] - cleaner *intervalCacheCleaner[T] -} - -type cacheItem[T any] struct { - item T - itemKey common.Hash - timeStored time.Time -} - -// NewBlockCache constructs a new cache. -func NewBlockCache[T any](evictionWindow time.Duration) *ocrCache[T] { - // Construct cache cleaner to evict old items. - cleaner := &intervalCacheCleaner[T]{ - interval: evictionWindow, - stop: make(chan struct{}, 1), - } - - // Instantiate the cache for type T. - cache := &ocrCache[T]{ - cacheMu: sync.Mutex{}, - cache: make(map[common.Hash]*cacheItem[T]), - evictionWindow: evictionWindow, - cleaner: cleaner, - } - - // Stop the cleaner upon garbage collection of the cache. - runtime.SetFinalizer(cache, func(b *ocrCache[T]) { b.cleaner.stop <- struct{}{} }) - - return cache -} - -// AddItem adds an item to the cache. -func (l *ocrCache[T]) CacheItem(item T, itemKey common.Hash, timeStored time.Time) { - // Construct new item to be stored. - newItem := &cacheItem[T]{ - item: item, - itemKey: itemKey, - timeStored: timeStored, - } - - // Lock, and defer unlock. - l.cacheMu.Lock() - defer l.cacheMu.Unlock() - - // Assign item to key. - l.cache[itemKey] = newItem -} - -func (l *ocrCache[T]) SetEvictonWindow(newWindow time.Duration) { - l.evictionWindow = newWindow -} - -// AddItem adds an item to the cache. -func (l *ocrCache[T]) GetItem(itemKey common.Hash) (item *T) { - // Lock, and defer unlock. - l.cacheMu.Lock() - defer l.cacheMu.Unlock() - - // Construct new item to be stored. - cacheItem := l.cache[itemKey] - - // Return nil if the item is not found, otherwise return item. - if cacheItem == nil { - return - } - - return &cacheItem.item -} - -// EvictExpiredItems removes all expired items stored in the cache. -func (l *ocrCache[T]) EvictExpiredItems(currentTime time.Time) { - // Lock, and defer unlock. - l.cacheMu.Lock() - defer l.cacheMu.Unlock() - - // Iteratively check all item ages, and delete an item if it is expired. - for key, item := range l.cache { - diff := currentTime.Sub(item.timeStored) - if diff > l.evictionWindow { - delete(l.cache, key) - } - } -} - -// A cache cleaner that evicts items on a regular interval. -type intervalCacheCleaner[T any] struct { - interval time.Duration - stop chan struct{} -} - -// Run evicts expired items every n seconds, until the "stop" channel is triggered. -func (ic *intervalCacheCleaner[T]) Run(c *ocrCache[T]) { - ticker := time.NewTicker(ic.interval) - for { - select { - case <-ticker.C: - c.EvictExpiredItems(time.Now().UTC()) - case <-ic.stop: - ticker.Stop() - return - } - } -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go deleted file mode 100644 index b4be43420b4..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package coordinator - -import ( - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" -) - -func TestNewCache(t *testing.T) { - b := NewBlockCache[int](time.Second) - - assert.Equal(t, time.Second, b.evictionWindow, "must set correct blockEvictionWindow") -} - -func TestCache(t *testing.T) { - t.Run("Happy path, no overwrites.", func(t *testing.T) { - now := time.Now().UTC() - - tests := []struct { - Key common.Hash - Value int - }{ - {Key: common.HexToHash("0x0"), Value: 1}, - {Key: common.HexToHash("0x1"), Value: 2}, - {Key: common.HexToHash("0x2"), Value: 3}, - {Key: common.HexToHash("0x3"), Value: 4}, - {Key: common.HexToHash("0x4"), Value: 5}, - } - - c := NewBlockCache[int](100 * time.Second) - - // Populate cache with ordered items. - for i, test := range tests { - c.CacheItem(test.Value, test.Key, getSecondsAfterNow(now, i)) - item := c.GetItem(test.Key) - assert.Equal(t, test.Value, *item) - } - - // Ensure cache has 5 items, with the newest and oldest pointers correct. - assert.Equal(t, 5, len(c.cache), "cache should contain 5 keys") - - // Evict all items. - evictionTime := getSecondsAfterNow(now, 105) - c.EvictExpiredItems(evictionTime) - assert.Equal(t, 0, len(c.cache), "cache should contain 0 keys") - - // Cache a new item. - c.CacheItem(tests[0].Value, tests[0].Key, getSecondsAfterNow(now, 10)) - item := c.GetItem(tests[0].Key) - assert.Equal(t, tests[0].Value, *item) - - // Attempting a new eviction should have no effect. - c.EvictExpiredItems(evictionTime) - assert.Equal(t, 1, len(c.cache), "cache should contain 1 key") - - // Reduce eviction window. - c.SetEvictonWindow(time.Second * 50) - - // Attempting a new eviction will remove the added item. - c.EvictExpiredItems(evictionTime) - assert.Equal(t, 0, len(c.cache), "cache should contain 0 keys") - }) - - t.Run("Happy path, override middle item.", func(t *testing.T) { - now := time.Now().UTC() - - tests := []struct { - Key common.Hash - Value int - }{ - {Key: common.HexToHash("0x0"), Value: 1}, - {Key: common.HexToHash("0x1"), Value: 2}, - {Key: common.HexToHash("0x2"), Value: 3}, - {Key: common.HexToHash("0x3"), Value: 4}, - {Key: common.HexToHash("0x1"), Value: 5}, - } - - c := NewBlockCache[int](100 * time.Second) - - // Populate cache with items. - for i, test := range tests { - c.CacheItem(test.Value, test.Key, getSecondsAfterNow(now, i)) - item := c.GetItem(test.Key) - assert.Equal(t, test.Value, *item) - } - - // Ensure cache has 4 items, with the newest and oldest pointers correct. - assert.Equal(t, 4, len(c.cache), "cache should contain 4 keys") - - // Evict all but two items. - c.EvictExpiredItems(getSecondsAfterNow(now, 103)) - assert.Equal(t, 2, len(c.cache), "cache should contain 2 keys") - - // Evict all but one items. - c.EvictExpiredItems(getSecondsAfterNow(now, 104)) - assert.Equal(t, 1, len(c.cache), "cache should contain 1 keys") - - // Evict remaining item. - c.EvictExpiredItems(getSecondsAfterNow(now, 105)) - assert.Equal(t, 0, len(c.cache), "cache should contain 0 keys") - }) - - t.Run("Happy path, override last item.", func(t *testing.T) { - now := time.Now().UTC() - - tests := []struct { - Key common.Hash - Value int - }{ - {Key: common.HexToHash("0x0"), Value: 1}, - {Key: common.HexToHash("0x1"), Value: 2}, - {Key: common.HexToHash("0x2"), Value: 3}, - {Key: common.HexToHash("0x3"), Value: 4}, - {Key: common.HexToHash("0x0"), Value: 5}, - } - - c := NewBlockCache[int](100 * time.Second) - - // Populate cache with items. - for i, test := range tests { - c.CacheItem(test.Value, test.Key, getSecondsAfterNow(now, i)) - item := c.GetItem(test.Key) - assert.Equal(t, test.Value, *item) - } - - // Ensure cache has 4 items, with the newest and oldest pointers correct. - assert.Equal(t, 4, len(c.cache), "cache should contain 4 keys") - - // Evict all but one item. - c.EvictExpiredItems(getSecondsAfterNow(now, 104)) - assert.Equal(t, 1, len(c.cache), "cache should contain 1 keys") - - // Cache a new item. - c.CacheItem(tests[1].Value, tests[1].Key, getSecondsAfterNow(now, 110)) - item := c.GetItem(tests[1].Key) - assert.Equal(t, tests[1].Value, *item) - - // Assert correct length. - assert.Equal(t, 2, len(c.cache), "cache should contain 2 keys") - - // Replace the oldest item. - c.CacheItem(tests[0].Value, tests[0].Key, getSecondsAfterNow(now, 111)) - item = c.GetItem(tests[0].Key) - assert.Equal(t, tests[0].Value, *item) - - // Assert correct length. - assert.Equal(t, 2, len(c.cache), "cache should contain 2 keys") - - // Replace the newest item. - c.CacheItem(tests[0].Value, tests[0].Key, getSecondsAfterNow(now, 112)) - item = c.GetItem(tests[0].Key) - assert.Equal(t, tests[0].Value, *item) - - // Assert correct length. - assert.Equal(t, 2, len(c.cache), "cache should contain 2 keys") - }) -} - -func getSecondsAfterNow(now time.Time, i int) time.Time { - return now.Add(time.Duration(i) * time.Second) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go deleted file mode 100644 index 77384a085ab..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go +++ /dev/null @@ -1,82 +0,0 @@ -package coordinator - -import ( - "math/big" - - "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" - - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -var _ VRFBeaconCoordinator = &vrfRouter{} - -// VRFProxy routes requests to VRFBeacon and VRFCoordinator go wrappers and implements VRFBeaconCoordinator interface -type vrfRouter struct { - lggr logger.Logger - beacon vrf_beacon.VRFBeaconInterface - coordinator vrf_coordinator.VRFCoordinatorInterface -} - -func newRouter( - lggr logger.Logger, - beaconAddress common.Address, - coordinatorAddress common.Address, - client evmclient.Client, -) (VRFBeaconCoordinator, error) { - beacon, err := vrf_beacon.NewVRFBeacon(beaconAddress, client) - if err != nil { - return nil, errors.Wrap(err, "beacon wrapper creation") - } - coordinator, err := vrf_coordinator.NewVRFCoordinator(coordinatorAddress, client) - if err != nil { - return nil, errors.Wrap(err, "coordinator wrapper creation") - } - return &vrfRouter{ - lggr: lggr, - beacon: beacon, - coordinator: coordinator, - }, nil -} - -// SProvingKeyHash retrieves the proving key hash from the on-chain contract. -// Calls VRF beacon wrapper to retrieve proving key hash -func (v *vrfRouter) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { - return v.beacon.SProvingKeyHash(opts) -} - -// SKeyID retrieves the keyID from the on-chain contract. -// Calls VRF beacon wrapper to retrieve key ID -func (v *vrfRouter) SKeyID(opts *bind.CallOpts) ([32]byte, error) { - return v.beacon.SKeyID(opts) -} - -// IBeaconPeriodBlocks retrieves the beacon period in blocks from the on-chain contract. -// Calls VRF coordinator wrapper to beacon period blocks -func (v *vrfRouter) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { - return v.coordinator.IBeaconPeriodBlocks(opts) -} - -// ParseLog parses the raw log data and topics into a go object. -// The returned object must be casted to the expected type. -// Calls either VRF beacon wrapper or VRF coordinator wrapper depending on the addresses of the log -func (v *vrfRouter) ParseLog(log types.Log) (generated.AbigenLog, error) { - if log.Address == v.beacon.Address() { - return v.beacon.ParseLog(log) - } else if log.Address == v.coordinator.Address() { - return v.coordinator.ParseLog(log) - } - return nil, errors.Errorf("failed to parse log. contractAddress: %x logs: %x", log.Address, log.Topics) -} - -// GetConfirmationDelays retrieves confirmation delays from the on-chain contract. -// Calls VRF coordinator to retrieve confirmation delays -func (v *vrfRouter) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { - return v.coordinator.GetConfirmationDelays(opts) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/router_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/router_test.go deleted file mode 100644 index 7135fa862e3..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/router_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package coordinator - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks" -) - -var nilOpts *bind.CallOpts - -func TestRouter_SProvingKeyHash(t *testing.T) { - beacon := mocks.NewVRFBeaconInterface(t) - keyHash := [32]byte{1} - router := vrfRouter{ - beacon: beacon, - } - beacon.On("SProvingKeyHash", mock.Anything).Return(keyHash, nil).Once() - - result, err := router.SProvingKeyHash(nilOpts) - assert.NoError(t, err) - assert.Equal(t, keyHash, result) -} - -func TestRouter_SKeyID(t *testing.T) { - beacon := mocks.NewVRFBeaconInterface(t) - keyID := [32]byte{2} - router := vrfRouter{ - beacon: beacon, - } - beacon.On("SKeyID", mock.Anything).Return(keyID, nil).Once() - - result, err := router.SKeyID(nilOpts) - assert.NoError(t, err) - assert.Equal(t, keyID, result) -} - -func TestRouter_IBeaconPeriodBlocks(t *testing.T) { - coordinator := mocks.NewVRFCoordinatorInterface(t) - periodBlocks := big.NewInt(3) - router := vrfRouter{ - coordinator: coordinator, - } - coordinator.On("IBeaconPeriodBlocks", mock.Anything).Return(periodBlocks, nil).Once() - - result, err := router.IBeaconPeriodBlocks(nilOpts) - assert.NoError(t, err) - assert.Equal(t, periodBlocks, result) -} - -func TestRouter_GetConfirmationDelays(t *testing.T) { - coordinator := mocks.NewVRFCoordinatorInterface(t) - confDelays := [8]*big.Int{big.NewInt(4)} - router := vrfRouter{ - coordinator: coordinator, - } - coordinator.On("GetConfirmationDelays", mock.Anything).Return(confDelays, nil).Once() - - result, err := router.GetConfirmationDelays(nilOpts) - assert.NoError(t, err) - assert.Equal(t, confDelays, result) -} - -func TestRouter_ParseLog(t *testing.T) { - t.Parallel() - - t.Run("parse beacon log", func(t *testing.T) { - addr := newAddress(t) - log := types.Log{ - Address: addr, - } - parsedLog := vrf_beacon.VRFBeaconNewTransmission{} - beacon := mocks.NewVRFBeaconInterface(t) - router := vrfRouter{ - beacon: beacon, - } - beacon.On("Address").Return(addr).Once() - beacon.On("ParseLog", log).Return(parsedLog, nil).Once() - - result, err := router.ParseLog(log) - assert.NoError(t, err) - assert.Equal(t, result, parsedLog) - }) - - t.Run("parse coordinator log", func(t *testing.T) { - addr := newAddress(t) - log := types.Log{ - Address: addr, - } - parsedLog := vrf_coordinator.VRFCoordinatorRandomnessRequested{} - beacon := mocks.NewVRFBeaconInterface(t) - coordinator := mocks.NewVRFCoordinatorInterface(t) - router := vrfRouter{ - beacon: beacon, - coordinator: coordinator, - } - beacon.On("Address").Return(newAddress(t)).Once() - coordinator.On("Address").Return(addr).Once() - coordinator.On("ParseLog", log).Return(parsedLog, nil).Once() - - result, err := router.ParseLog(log) - assert.NoError(t, err) - assert.Equal(t, result, parsedLog) - }) - - t.Run("parse log unexpected log", func(t *testing.T) { - log := types.Log{ - Address: newAddress(t), - } - beacon := mocks.NewVRFBeaconInterface(t) - coordinator := mocks.NewVRFCoordinatorInterface(t) - router := vrfRouter{ - beacon: beacon, - coordinator: coordinator, - } - beacon.On("Address").Return(newAddress(t)).Once() - coordinator.On("Address").Return(newAddress(t)).Once() - - result, err := router.ParseLog(log) - assert.Nil(t, result) - assert.Contains(t, err.Error(), "failed to parse log") - }) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/topics.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/topics.go deleted file mode 100644 index 370f0c5fd00..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/topics.go +++ /dev/null @@ -1,28 +0,0 @@ -package coordinator - -import ( - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" -) - -type topics struct { - randomnessRequestedTopic common.Hash - randomnessFulfillmentRequestedTopic common.Hash - randomWordsFulfilledTopic common.Hash - configSetTopic common.Hash - newTransmissionTopic common.Hash - outputsServedTopic common.Hash -} - -func newTopics() topics { - return topics{ - randomnessRequestedTopic: vrf_coordinator.VRFCoordinatorRandomnessRequested{}.Topic(), - randomnessFulfillmentRequestedTopic: vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested{}.Topic(), - randomWordsFulfilledTopic: vrf_coordinator.VRFCoordinatorRandomWordsFulfilled{}.Topic(), - configSetTopic: vrf_beacon.VRFBeaconConfigSet{}.Topic(), - newTransmissionTopic: vrf_beacon.VRFBeaconNewTransmission{}.Topic(), - outputsServedTopic: vrf_coordinator.VRFCoordinatorOutputsServed{}.Topic(), - } -} diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go deleted file mode 100644 index ee722587de6..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ /dev/null @@ -1,884 +0,0 @@ -package internal_test - -import ( - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/ethclient/simulated" - "github.com/hashicorp/consul/sdk/freeport" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - "go.dedis.ch/kyber/v3" - - "github.com/smartcontractkit/libocr/commontypes" - confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - ocr2dkg "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" - dkg_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/load_test_beacon_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" - vrf_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "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/validate" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" -) - -type ocr2vrfUniverse struct { - owner *bind.TransactOpts - backend *simulated.Backend - - dkgAddress common.Address - dkg *dkg_wrapper.DKG - - beaconAddress common.Address - coordinatorAddress common.Address - beacon *vrf_beacon.VRFBeacon - coordinator *vrf_wrapper.VRFCoordinator - - linkAddress common.Address - link *link_token_interface.LinkToken - - consumerAddress common.Address - consumer *vrf_beacon_consumer.BeaconVRFConsumer - - loadTestConsumerAddress common.Address - loadTestConsumer *load_test_beacon_consumer.LoadTestBeaconVRFConsumer - - feedAddress common.Address - feed *mock_v3_aggregator_contract.MockV3AggregatorContract - - subID *big.Int -} - -const ( - fundingAmount int64 = 5e18 -) - -type ocr2Node struct { - app *cltest.TestApplication - peerID string - transmitter common.Address - effectiveTransmitter common.Address - keybundle ocr2key.KeyBundle - sendingKeys []string -} - -func setupOCR2VRFContracts( - t *testing.T, beaconPeriod int64, keyID [32]byte, consumerShouldFail bool) ocr2vrfUniverse { - owner := testutils.MustNewSimTransactor(t) - owner.GasPrice = assets.GWei(1).ToInt() - genesisData := types.GenesisAlloc{ - owner.From: { - Balance: assets.Ether(100).ToInt(), - }, - } - b := simulated.NewBackend(genesisData, simulated.WithBlockGasLimit(ethconfig.Defaults.Miner.GasCeil*2)) - - // deploy OCR2VRF contracts, which have the following deploy order: - // * link token - // * link/eth feed - // * DKG - // * VRF (coordinator, and beacon) - // * VRF consumer - linkAddress, _, link, err := link_token_interface.DeployLinkToken( - owner, b.Client()) - require.NoError(t, err) - b.Commit() - - feedAddress, _, feed, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract( - owner, b.Client(), 18, assets.GWei(int(1e7)).ToInt()) // 0.01 eth per link - require.NoError(t, err) - b.Commit() - - dkgAddress, _, dkg, err := dkg_wrapper.DeployDKG(owner, b.Client()) - require.NoError(t, err) - b.Commit() - - coordinatorAddress, _, coordinator, err := vrf_wrapper.DeployVRFCoordinator( - owner, b.Client(), big.NewInt(beaconPeriod), linkAddress) - require.NoError(t, err) - b.Commit() - - require.NoError(t, commonutils.JustError(coordinator.SetCallbackConfig(owner, vrf_wrapper.VRFCoordinatorCallbackConfig{ - MaxCallbackGasLimit: 2.5e6, - MaxCallbackArgumentsLength: 160, // 5 EVM words - }))) - b.Commit() - - require.NoError(t, commonutils.JustError(coordinator.SetCoordinatorConfig(owner, vrf_wrapper.VRFBeaconTypesCoordinatorConfig{ - RedeemableRequestGasOverhead: 50_000, - CallbackRequestGasOverhead: 50_000, - StalenessSeconds: 60, - FallbackWeiPerUnitLink: assets.GWei(int(1e7)).ToInt(), - }))) - b.Commit() - - beaconAddress, _, beacon, err := vrf_beacon.DeployVRFBeacon( - owner, b.Client(), linkAddress, coordinatorAddress, dkgAddress, keyID) - require.NoError(t, err) - b.Commit() - - consumerAddress, _, consumer, err := vrf_beacon_consumer.DeployBeaconVRFConsumer( - owner, b.Client(), coordinatorAddress, consumerShouldFail, big.NewInt(beaconPeriod)) - require.NoError(t, err) - b.Commit() - - loadTestConsumerAddress, _, loadTestConsumer, err := load_test_beacon_consumer.DeployLoadTestBeaconVRFConsumer( - owner, b.Client(), coordinatorAddress, consumerShouldFail, big.NewInt(beaconPeriod)) - require.NoError(t, err) - b.Commit() - - // Set up coordinator subscription for billing. - require.NoError(t, commonutils.JustError(coordinator.CreateSubscription(owner))) - b.Commit() - - fopts := &bind.FilterOpts{} - - subscriptionIterator, err := coordinator.FilterSubscriptionCreated(fopts, nil, []common.Address{owner.From}) - require.NoError(t, err) - - require.True(t, subscriptionIterator.Next()) - subID := subscriptionIterator.Event.SubId - - require.NoError(t, commonutils.JustError(coordinator.AddConsumer(owner, subID, consumerAddress))) - b.Commit() - require.NoError(t, commonutils.JustError(coordinator.AddConsumer(owner, subID, loadTestConsumerAddress))) - b.Commit() - data, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) - require.NoError(t, err) - require.NoError(t, commonutils.JustError(link.TransferAndCall(owner, coordinatorAddress, big.NewInt(5e18), data))) - b.Commit() - - _, err = dkg.AddClient(owner, keyID, beaconAddress) - require.NoError(t, err) - b.Commit() - - _, err = coordinator.SetProducer(owner, beaconAddress) - require.NoError(t, err) - - // Achieve finality depth so the CL node can work properly. - for i := 0; i < 20; i++ { - b.Commit() - } - - return ocr2vrfUniverse{ - owner: owner, - backend: b, - dkgAddress: dkgAddress, - dkg: dkg, - beaconAddress: beaconAddress, - coordinatorAddress: coordinatorAddress, - beacon: beacon, - coordinator: coordinator, - linkAddress: linkAddress, - link: link, - consumerAddress: consumerAddress, - consumer: consumer, - loadTestConsumerAddress: loadTestConsumerAddress, - loadTestConsumer: loadTestConsumer, - feedAddress: feedAddress, - feed: feed, - subID: subID, - } -} - -func setupNodeOCR2( - t *testing.T, - owner *bind.TransactOpts, - port int, - dbName string, - b *simulated.Backend, - 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. - - c.Feature.LogPoller = ptr(true) - - c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} - if len(p2pV2Bootstrappers) > 0 { - c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers - } - - c.OCR.Enabled = ptr(false) - c.OCR2.Enabled = ptr(true) - - c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(500 * time.Millisecond) - c.EVM[0].GasEstimator.LimitDefault = ptr[uint64](3_500_000) - c.EVM[0].Transactions.ForwardersEnabled = &useForwarders - c.OCR2.ContractPollInterval = commonconfig.MustNewDuration(10 * time.Second) - }) - - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - - var sendingKeys []ethkey.KeyV2 - { - var err error - sendingKeys, err = app.KeyStore.Eth().EnabledKeysForChain(ctx, testutils.SimulatedChainID) - require.NoError(t, err) - require.Len(t, sendingKeys, 1) - } - transmitter := sendingKeys[0].Address - effectiveTransmitter := sendingKeys[0].Address - - if useForwarders { - sendingKeysAddresses := []common.Address{sendingKeys[0].Address} - - // Add new sending key. - k, err := app.KeyStore.Eth().Create(ctx) - require.NoError(t, err) - 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) - - require.Len(t, sendingKeys, 2) - - // Deploy a forwarder. - faddr, _, authorizedForwarder, err := authorized_forwarder.DeployAuthorizedForwarder(owner, b.Client(), common.HexToAddress("0x326C977E6efc84E512bB9C30f76E30c160eD06FB"), owner.From, common.Address{}, []byte{}) - require.NoError(t, err) - - // Set the node's sending keys as authorized senders. - _, err = authorizedForwarder.SetAuthorizedSenders(owner, sendingKeysAddresses) - require.NoError(t, err) - b.Commit() - - // Add the forwarder to the node's forwarder manager. - forwarderORM := forwarders.NewORM(app.GetDB()) - chainID := ubig.Big(*testutils.SimulatedChainID) - _, err = forwarderORM.CreateForwarder(testutils.Context(t), faddr, chainID) - require.NoError(t, err) - effectiveTransmitter = faddr - } - - // Fund the sending keys with some ETH. - var sendingKeyStrings []string - for _, k := range sendingKeys { - sendingKeyStrings = append(sendingKeyStrings, k.Address.String()) - n, err := b.Client().NonceAt(ctx, owner.From, nil) - require.NoError(t, err) - - tx := cltest.NewLegacyTransaction( - n, k.Address, - assets.Ether(1).ToInt(), - 21000, - assets.GWei(1).ToInt(), - nil) - signedTx, err := owner.Signer(owner.From, tx) - require.NoError(t, err) - err = b.Client().SendTransaction(ctx, signedTx) - require.NoError(t, err) - b.Commit() - } - - kb, err := app.GetKeyStore().OCR2().Create(ctx, "evm") - require.NoError(t, err) - - return &ocr2Node{ - app: app, - peerID: p2pKey.PeerID().Raw(), - transmitter: transmitter, - effectiveTransmitter: effectiveTransmitter, - keybundle: kb, - sendingKeys: sendingKeyStrings, - } -} - -func TestIntegration_OCR2VRF_ForwarderFlow(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-688") - runOCR2VRFTest(t, true) -} - -func TestIntegration_OCR2VRF(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/VRF-688") - runOCR2VRFTest(t, false) -} - -func runOCR2VRFTest(t *testing.T, useForwarders bool) { - ctx := testutils.Context(t) - keyID := randomKeyID(t) - uni := setupOCR2VRFContracts(t, 5, keyID, false) - - t.Log("Creating bootstrap node") - - bootstrapNodePort := freeport.GetOne(t) - bootstrapNode := setupNodeOCR2(t, uni.owner, bootstrapNodePort, "bootstrap", uni.backend, false, nil) - numNodes := 5 - - t.Log("Creating OCR2 nodes") - var ( - oracles []confighelper2.OracleIdentityExtra - transmitters []common.Address - payees []common.Address - payeeTransactors []*bind.TransactOpts - effectiveTransmitters []common.Address - onchainPubKeys []common.Address - kbs []ocr2key.KeyBundle - apps []*cltest.TestApplication - dkgEncrypters []dkgencryptkey.Key - dkgSigners []dkgsignkey.Key - sendingKeys [][]string - ) - ports := freeport.GetN(t, numNodes) - for i := 0; i < numNodes; i++ { - // Supply the bootstrap IP and port as a V2 peer address - bootstrappers := []commontypes.BootstrapperLocator{ - {PeerID: bootstrapNode.peerID, Addrs: []string{ - fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort), - }}, - } - node := setupNodeOCR2(t, uni.owner, ports[i], fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) - sendingKeys = append(sendingKeys, node.sendingKeys) - - dkgSignKey, err := node.app.GetKeyStore().DKGSign().Create(ctx) - require.NoError(t, err) - - dkgEncryptKey, err := node.app.GetKeyStore().DKGEncrypt().Create(ctx) - require.NoError(t, err) - - kbs = append(kbs, node.keybundle) - apps = append(apps, node.app) - transmitters = append(transmitters, node.transmitter) - payeeTransactor := testutils.MustNewSimTransactor(t) - payeeTransactors = append(payeeTransactors, payeeTransactor) - payees = append(payees, payeeTransactor.From) - effectiveTransmitters = append(effectiveTransmitters, node.effectiveTransmitter) - dkgEncrypters = append(dkgEncrypters, dkgEncryptKey) - dkgSigners = append(dkgSigners, dkgSignKey) - onchainPubKeys = append(onchainPubKeys, common.BytesToAddress(node.keybundle.PublicKey())) - oracles = append(oracles, confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: node.keybundle.PublicKey(), - TransmitAccount: ocrtypes2.Account(node.transmitter.String()), - OffchainPublicKey: node.keybundle.OffchainPublicKey(), - PeerID: node.peerID, - }, - ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), - }) - } - - _, err := uni.beacon.SetPayees(uni.owner, transmitters, payees) - require.NoError(t, err) - - t.Log("starting ticker to commit blocks") - tick := time.NewTicker(1 * time.Second) - defer tick.Stop() - go func() { - for range tick.C { - uni.backend.Commit() - } - }() - - blockBeforeConfig, err := uni.backend.Client().BlockByNumber(ctx, nil) - require.NoError(t, err) - - t.Log("Setting DKG config before block:", blockBeforeConfig.Number().String()) - - // set config for dkg - setDKGConfig( - t, - uni, - onchainPubKeys, - effectiveTransmitters, - 1, - oracles, - dkgSigners, - dkgEncrypters, - keyID, - ) - - t.Log("Adding bootstrap node job") - err = bootstrapNode.app.Start(ctx) - require.NoError(t, err) - - evmChains := bootstrapNode.app.GetRelayers().LegacyEVMChains() - require.NotNil(t, evmChains) - bootstrapJobSpec := fmt.Sprintf(` -type = "bootstrap" -name = "bootstrap" -contractConfigTrackerPollInterval = "15s" -relay = "evm" -schemaVersion = 1 -contractID = "%s" -[relayConfig] -chainID = 1337 -fromBlock = %d -`, uni.dkgAddress.Hex(), blockBeforeConfig.Number().Int64()) - t.Log("Creating bootstrap job:", bootstrapJobSpec) - ocrJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(bootstrapJobSpec) - require.NoError(t, err) - err = bootstrapNode.app.AddJobV2(ctx, &ocrJob) - require.NoError(t, err) - - t.Log("Creating OCR2VRF jobs") - for i := 0; i < numNodes; i++ { - var sendingKeysString = fmt.Sprintf(`"%s"`, sendingKeys[i][0]) - for x := 1; x < len(sendingKeys[i]); x++ { - sendingKeysString = fmt.Sprintf(`%s,"%s"`, sendingKeysString, sendingKeys[i][x]) - } - err = apps[i].Start(ctx) - require.NoError(t, err) - - jobSpec := fmt.Sprintf(` -type = "offchainreporting2" -schemaVersion = 1 -name = "ocr2 vrf integration test" -maxTaskDuration = "30s" -contractID = "%s" -ocrKeyBundleID = "%s" -relay = "evm" -pluginType = "ocr2vrf" -transmitterID = "%s" -forwardingAllowed = %t -contractConfigTrackerPollInterval = "15s" - -[relayConfig] -chainID = 1337 -fromBlock = %d - -[pluginConfig] -dkgEncryptionPublicKey = "%s" -dkgSigningPublicKey = "%s" -dkgKeyID = "%s" -dkgContractAddress = "%s" - -vrfCoordinatorAddress = "%s" -linkEthFeedAddress = "%s" -`, uni.beaconAddress.String(), - kbs[i].ID(), - transmitters[i], - useForwarders, - blockBeforeConfig.Number().Int64(), - dkgEncrypters[i].PublicKeyString(), - dkgSigners[i].PublicKeyString(), - hex.EncodeToString(keyID[:]), - uni.dkgAddress.String(), - uni.coordinatorAddress.String(), - uni.feedAddress.String(), - ) - t.Log("Creating OCR2VRF job with spec:", jobSpec) - ocrJob2, err2 := validate.ValidatedOracleSpecToml(testutils.Context(t), apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec, nil) - require.NoError(t, err2) - err2 = apps[i].AddJobV2(ctx, &ocrJob2) - require.NoError(t, err2) - } - - t.Log("Waiting for DKG key to get written") - // poll until a DKG key is written to the contract - // at that point we can start sending VRF requests - var emptyKH [32]byte - emptyHash := crypto.Keccak256Hash(emptyKH[:]) - gomega.NewWithT(t).Eventually(func() bool { - kh, err2 := uni.beacon.SProvingKeyHash(&bind.CallOpts{ - Context: ctx, - }) - require.NoError(t, err2) - t.Log("proving keyhash:", hexutil.Encode(kh[:])) - return crypto.Keccak256Hash(kh[:]) != emptyHash - }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) - - t.Log("DKG key written, setting VRF config") - - // set config for vrf now that dkg is ready - setVRFConfig( - t, - uni, - onchainPubKeys, - effectiveTransmitters, - 1, - oracles, - []int{1, 2, 3, 4, 5, 6, 7, 8}, - keyID) - - t.Log("Sending VRF request") - - initialSub, err := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err) - require.Equal(t, assets.Ether(5).ToInt(), initialSub.Balance) - - // Send a beacon VRF request and mine it - _, err = uni.consumer.TestRequestRandomness(uni.owner, 2, uni.subID, big.NewInt(1)) - require.NoError(t, err) - uni.backend.Commit() - - redemptionRequestID, err := uni.consumer.SMostRecentRequestID(nil) - require.NoError(t, err) - - // There is no premium on this request, so the cost of the request should have been: - // = (request overhead) * (gas price) / (LINK/ETH ratio) - // = (50_000 * 1 Gwei) / .01 - // = 5_000_000 GJuels - subAfterBeaconRequest, err := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err) - require.Equal(t, big.NewInt(initialSub.Balance.Int64()-assets.GWei(5_000_000).Int64()), subAfterBeaconRequest.Balance) - - // Send a fulfillment VRF request and mine it - _, err = uni.consumer.TestRequestRandomnessFulfillment(uni.owner, uni.subID, 1, big.NewInt(2), 100_000, []byte{}) - require.NoError(t, err) - uni.backend.Commit() - - fulfillmentRequestID, err := uni.consumer.SMostRecentRequestID(nil) - require.NoError(t, err) - - // There is no premium on this request, so the cost of the request should have been: - // = (request overhead + callback gas allowance) * (gas price) / (LINK/ETH ratio) - // = ((50_000 + 100_000) * 1 Gwei) / .01 - // = 15_000_000 GJuels - subAfterFulfillmentRequest, err := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err) - require.Equal(t, big.NewInt(subAfterBeaconRequest.Balance.Int64()-assets.GWei(15_000_000).Int64()), subAfterFulfillmentRequest.Balance) - - // Send two batched fulfillment VRF requests and mine them - _, err = uni.loadTestConsumer.TestRequestRandomnessFulfillmentBatch(uni.owner, uni.subID, 1, big.NewInt(2), 200_000, []byte{}, big.NewInt(2)) - require.NoError(t, err) - uni.backend.Commit() - - batchFulfillmentRequestID1, err := uni.loadTestConsumer.SRequestIDs(nil, big.NewInt(0), big.NewInt(0)) - require.NoError(t, err) - - batchFulfillmentRequestID2, err := uni.loadTestConsumer.SRequestIDs(nil, big.NewInt(0), big.NewInt(1)) - require.NoError(t, err) - - // There is no premium on these requests, so the cost of the requests should have been: - // = ((request overhead + callback gas allowance) * (gas price) / (LINK/ETH ratio)) * batch size - // = (((50_000 + 200_000) * 1 Gwei) / .01) * 2 - // = 50_000_000 GJuels - subAfterBatchFulfillmentRequest, err := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err) - require.Equal(t, big.NewInt(subAfterFulfillmentRequest.Balance.Int64()-assets.GWei(50_000_000).Int64()), subAfterBatchFulfillmentRequest.Balance) - - t.Logf("sub balance after batch fulfillment request: %d", subAfterBatchFulfillmentRequest.Balance) - - t.Log("waiting for fulfillment") - - var balanceAfterRefund *big.Int - // poll until we're able to redeem the randomness without reverting - // at that point, it's been fulfilled - gomega.NewWithT(t).Eventually(func() bool { - _, err2 := uni.consumer.TestRedeemRandomness(uni.owner, uni.subID, redemptionRequestID) - t.Logf("TestRedeemRandomness err: %+v", err2) - return err2 == nil - }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) - - gomega.NewWithT(t).Eventually(func() bool { - // Ensure a refund is provided. Refund amount comes out to ~15_700_000 GJuels. - // We use an upper and lower bound such that this part of the test is not excessively brittle to upstream tweaks. - refundUpperBound := big.NewInt(0).Add(assets.GWei(17_000_000).ToInt(), subAfterBatchFulfillmentRequest.Balance) - refundLowerBound := big.NewInt(0).Add(assets.GWei(15_000_000).ToInt(), subAfterBatchFulfillmentRequest.Balance) - subAfterRefund, err2 := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err2) - balanceAfterRefund = subAfterRefund.Balance - if ok := ((balanceAfterRefund.Cmp(refundUpperBound) == -1) && (balanceAfterRefund.Cmp(refundLowerBound) == 1)); !ok { - t.Logf("unexpected sub balance after refund: %d", balanceAfterRefund) - return false - } - return true - }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) - - // Mine block after redeeming randomness - uni.backend.Commit() - - // ensure that total sub balance is updated correctly - totalSubBalance, err := uni.coordinator.GetSubscriptionLinkBalance(nil) - require.NoError(t, err) - require.True(t, totalSubBalance.Cmp(balanceAfterRefund) == 0) - // ensure total link balance is correct before any payout - totalLinkBalance, err := uni.link.BalanceOf(nil, uni.coordinatorAddress) - require.NoError(t, err) - require.True(t, totalLinkBalance.Cmp(big.NewInt(fundingAmount)) == 0) - - // get total owed amount to NOPs and ensure linkAvailableForPayment (CLL profit) calculation is correct - nopOwedAmount := new(big.Int) - for _, transmitter := range transmitters { - owedAmount, err2 := uni.beacon.OwedPayment(nil, transmitter) - require.NoError(t, err2) - nopOwedAmount = new(big.Int).Add(nopOwedAmount, owedAmount) - } - linkAvailable, err := uni.beacon.LinkAvailableForPayment(nil) - require.NoError(t, err) - debt := new(big.Int).Add(totalSubBalance, nopOwedAmount) - profit := new(big.Int).Sub(totalLinkBalance, debt) - require.True(t, linkAvailable.Cmp(profit) == 0) - - // test cancel subscription - linkBalanceBeforeCancel, err := uni.link.BalanceOf(nil, uni.owner.From) - require.NoError(t, err) - _, err = uni.coordinator.CancelSubscription(uni.owner, uni.subID, uni.owner.From) - require.NoError(t, err) - uni.backend.Commit() - linkBalanceAfterCancel, err := uni.link.BalanceOf(nil, uni.owner.From) - require.NoError(t, err) - require.True(t, new(big.Int).Add(linkBalanceBeforeCancel, totalSubBalance).Cmp(linkBalanceAfterCancel) == 0) - totalSubBalance, err = uni.coordinator.GetSubscriptionLinkBalance(nil) - require.NoError(t, err) - require.True(t, totalSubBalance.Cmp(big.NewInt(0)) == 0) - totalLinkBalance, err = uni.link.BalanceOf(nil, uni.coordinatorAddress) - require.NoError(t, err) - require.True(t, totalLinkBalance.Cmp(new(big.Int).Sub(big.NewInt(fundingAmount), balanceAfterRefund)) == 0) - - // payout node operators - totalNopPayout := new(big.Int) - for idx, payeeTransactor := range payeeTransactors { - // Fund the payee with some ETH. - n, err2 := uni.backend.Client().NonceAt(ctx, uni.owner.From, nil) - require.NoError(t, err2) - tx := cltest.NewLegacyTransaction( - n, payeeTransactor.From, - assets.Ether(1).ToInt(), - 21000, - assets.GWei(1).ToInt(), - nil) - signedTx, err2 := uni.owner.Signer(uni.owner.From, tx) - require.NoError(t, err2) - err2 = uni.backend.Client().SendTransaction(ctx, signedTx) - require.NoError(t, err2) - - _, err2 = uni.beacon.WithdrawPayment(payeeTransactor, transmitters[idx]) - require.NoError(t, err2) - uni.backend.Commit() - payoutAmount, err2 := uni.link.BalanceOf(nil, payeeTransactor.From) - require.NoError(t, err2) - totalNopPayout = new(big.Int).Add(totalNopPayout, payoutAmount) - owedAmountAfter, err2 := uni.beacon.OwedPayment(nil, transmitters[idx]) - require.NoError(t, err2) - require.True(t, owedAmountAfter.Cmp(big.NewInt(0)) == 0) - } - require.True(t, nopOwedAmount.Cmp(totalNopPayout) == 0) - - // check total link balance after NOP payout - totalLinkBalanceAfterNopPayout, err := uni.link.BalanceOf(nil, uni.coordinatorAddress) - require.NoError(t, err) - require.True(t, totalLinkBalanceAfterNopPayout.Cmp(new(big.Int).Sub(totalLinkBalance, totalNopPayout)) == 0) - totalSubBalance, err = uni.coordinator.GetSubscriptionLinkBalance(nil) - require.NoError(t, err) - require.True(t, totalSubBalance.Cmp(big.NewInt(0)) == 0) - - // withdraw remaining profits after NOP payout - linkAvailable, err = uni.beacon.LinkAvailableForPayment(nil) - require.NoError(t, err) - linkBalanceBeforeWithdraw, err := uni.link.BalanceOf(nil, uni.owner.From) - require.NoError(t, err) - _, err = uni.beacon.WithdrawFunds(uni.owner, uni.owner.From, linkAvailable) - require.NoError(t, err) - uni.backend.Commit() - linkBalanceAfterWithdraw, err := uni.link.BalanceOf(nil, uni.owner.From) - require.NoError(t, err) - require.True(t, linkBalanceAfterWithdraw.Cmp(new(big.Int).Add(linkBalanceBeforeWithdraw, linkAvailable)) == 0) - linkAvailable, err = uni.beacon.LinkAvailableForPayment(nil) - require.NoError(t, err) - require.True(t, linkAvailable.Cmp(big.NewInt(0)) == 0) - - // poll until we're able to verify that consumer contract has stored randomness as expected - // First arg is the request ID, which starts at zero, second is the index into - // the random words. - gomega.NewWithT(t).Eventually(func() bool { - var errs []error - rw1, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(0)) - t.Logf("TestRedeemRandomness 1st word err: %+v", err2) - errs = append(errs, err2) - rw2, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(1)) - t.Logf("TestRedeemRandomness 2nd word err: %+v", err2) - errs = append(errs, err2) - rw3, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, fulfillmentRequestID, big.NewInt(0)) - t.Logf("FulfillRandomness 1st word err: %+v", err2) - errs = append(errs, err2) - rw4, err2 := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID1, big.NewInt(0)) - t.Logf("Batch FulfillRandomness 1st word err: %+v", err2) - errs = append(errs, err2) - rw5, err2 := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID2, big.NewInt(0)) - t.Logf("Batch FulfillRandomness 2nd word err: %+v", err2) - errs = append(errs, err2) - batchTotalRequests, err2 := uni.loadTestConsumer.STotalRequests(nil) - t.Logf("Batch FulfillRandomness total requests err: %+v", err2) - errs = append(errs, err2) - batchTotalFulfillments, err2 := uni.loadTestConsumer.STotalFulfilled(nil) - t.Logf("Batch FulfillRandomness total fulfillments err: %+v", err2) - errs = append(errs, err2) - err2 = nil - if batchTotalRequests.Int64() != batchTotalFulfillments.Int64() { - err2 = errors.New("batchTotalRequests is not equal to batchTotalFulfillments") - errs = append(errs, err2) - } - t.Logf("Batch FulfillRandomness total requests/fulfillments equal err: %+v", err2) - - t.Logf("randomness from redeemRandomness: %s %s", rw1.String(), rw2.String()) - t.Logf("randomness from fulfillRandomness: %s", rw3.String()) - t.Logf("randomness from batch fulfillRandomness: %s %s", rw4.String(), rw5.String()) - t.Logf("total batch requested and fulfilled: %d %d", batchTotalRequests, batchTotalFulfillments) - - for _, err := range errs { - if err != nil { - return false - } - } - return true - }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) -} - -func setDKGConfig( - t *testing.T, - uni ocr2vrfUniverse, - onchainPubKeys []common.Address, - transmitters []common.Address, - f uint8, - oracleIdentities []confighelper2.OracleIdentityExtra, - signKeys []dkgsignkey.Key, - encryptKeys []dkgencryptkey.Key, - keyID [32]byte, -) { - var ( - signingPubKeys []kyber.Point - encryptPubKeys []kyber.Point - ) - for i := range signKeys { - signingPubKeys = append(signingPubKeys, signKeys[i].PublicKey) - encryptPubKeys = append(encryptPubKeys, encryptKeys[i].PublicKey) - } - - offchainConfig, err := ocr2dkg.OffchainConfig( - encryptPubKeys, - signingPubKeys, - &altbn_128.G1{}, - &ocr2vrftypes.PairingTranslation{ - Suite: &altbn_128.PairingSuite{}, - }) - require.NoError(t, err) - onchainConfig, err := ocr2dkg.OnchainConfig(keyID) - require.NoError(t, err) - - var schedule []int - for range oracleIdentities { - schedule = append(schedule, 1) - } - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper2.ContractSetConfigArgsForTests( - 30*time.Second, - 10*time.Second, - 20*time.Second, - 2*time.Second, - 20*time.Second, - 3, - schedule, - oracleIdentities, - offchainConfig, - 50*time.Millisecond, - 10*time.Second, - 10*time.Second, - 100*time.Millisecond, - 1*time.Second, - int(f), - onchainConfig) - require.NoError(t, err) - - _, err = uni.dkg.SetConfig(uni.owner, onchainPubKeys, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - require.NoError(t, err) - - uni.backend.Commit() -} - -func setVRFConfig( - t *testing.T, - uni ocr2vrfUniverse, - onchainPubKeys []common.Address, - transmitters []common.Address, - f uint8, - oracleIdentities []confighelper2.OracleIdentityExtra, - confDelaysSl []int, - keyID [32]byte, -) { - offchainConfig := ocr2vrf.OffchainConfig(&ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: 1, - BatchGasLimit: 5_000_000, - CoordinatorOverhead: 50_000, - CallbackOverhead: 50_000, - BlockGasOverhead: 50_000, - LookbackBlocks: 1_000, - }) - - confDelays := make(map[uint32]struct{}) - for _, c := range confDelaysSl { - confDelays[uint32(c)] = struct{}{} - } - - onchainConfig := ocr2vrf.OnchainConfig(confDelays) - - var schedule []int - for range oracleIdentities { - schedule = append(schedule, 1) - } - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper2.ContractSetConfigArgsForTests( - 30*time.Second, - 10*time.Second, - 20*time.Second, - 2*time.Second, - 20*time.Second, - 3, - schedule, - oracleIdentities, - offchainConfig, - 50*time.Millisecond, - 10*time.Second, - 10*time.Second, - 100*time.Millisecond, - 1*time.Second, - int(f), - onchainConfig) - require.NoError(t, err) - - _, err = uni.beacon.SetConfig( - uni.owner, onchainPubKeys, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) - require.NoError(t, err) - - uni.backend.Commit() -} - -func randomKeyID(t *testing.T) (r [32]byte) { - _, err := rand.Read(r[:]) - require.NoError(t, err) - return -} - -func ptr[T any](v T) *T { return &v } diff --git a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go b/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go deleted file mode 100644 index 2601ae14668..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider.go +++ /dev/null @@ -1,109 +0,0 @@ -package juelsfeecoin - -import ( - "context" - "math/big" - "runtime" - "sync" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-vrf/types" - - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -// linkEthPriceProvider provides conversation rate between Link and native token using price feeds -type linkEthPriceProvider struct { - aggregator aggregator_v3_interface.AggregatorV3InterfaceInterface - timeout time.Duration - interval time.Duration - lock sync.RWMutex - stop chan struct{} - currentJuelsPerFeeCoin *big.Int - lggr logger.Logger -} - -var _ types.JuelsPerFeeCoin = (*linkEthPriceProvider)(nil) - -func NewLinkEthPriceProvider( - linkEthFeedAddress common.Address, - client evmclient.Client, - timeout time.Duration, - interval time.Duration, - logger logger.Logger, -) (types.JuelsPerFeeCoin, error) { - aggregator, err := aggregator_v3_interface.NewAggregatorV3Interface(linkEthFeedAddress, client) - if err != nil { - return nil, errors.Wrap(err, "new aggregator v3 interface") - } - - if timeout >= interval { - return nil, errors.New("timeout must be less than interval") - } - - p := &linkEthPriceProvider{ - aggregator: aggregator, - timeout: timeout, - interval: interval, - currentJuelsPerFeeCoin: big.NewInt(0), - stop: make(chan struct{}), - lggr: logger, - } - - // Begin updating JuelsPerFeeCoin. - // Stop fetching price updates on garbage collection, as to avoid a leaked goroutine. - go p.run() - runtime.SetFinalizer(p, func(p *linkEthPriceProvider) { p.stop <- struct{}{} }) - - return p, nil -} - -// Run updates the JuelsPerFeeCoin value at a regular interval, until stopped. -// Do not block the main thread, such that updates are always timely. -func (p *linkEthPriceProvider) run() { - ticker := time.NewTicker(p.interval) - for { - select { - case <-ticker.C: - go p.updateJuelsPerFeeCoin() - case <-p.stop: - ticker.Stop() - return - } - } -} - -// JuelsPerFeeCoin returns the current JuelsPerFeeCoin value, threadsafe. -func (p *linkEthPriceProvider) JuelsPerFeeCoin() (*big.Int, error) { - p.lock.RLock() - defer p.lock.RUnlock() - return p.currentJuelsPerFeeCoin, nil -} - -// Get current JuelsPerFeeCoin value from aggregator contract. -// If the RPC call fails, log the error and return. -func (p *linkEthPriceProvider) updateJuelsPerFeeCoin() { - // Ensure writes to currentJuelsPerFeeCoin are threadsafe. - p.lock.Lock() - defer p.lock.Unlock() - - ctx, cancel := context.WithTimeout(context.Background(), p.timeout) - defer cancel() - roundData, err := p.aggregator.LatestRoundData(&bind.CallOpts{Context: ctx}) - - // For RPC issues, set the most recent price to 0. This way, stale prices will not be transmitted, - // and zero-observations can be ignored in OCR and on-chain. - if err != nil { - p.currentJuelsPerFeeCoin = big.NewInt(0) - return - } - - // Update JuelsPerFeeCoin to the obtained value. - p.currentJuelsPerFeeCoin = roundData.Answer -} diff --git a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider_test.go b/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider_test.go deleted file mode 100644 index 73a66d17ead..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/juelsfeecoin/link_eth_price_provider_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package juelsfeecoin - -import ( - "errors" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/vrf/mocks" -) - -func Test_JuelsPerFeeCoin(t *testing.T) { - t.Parallel() - - t.Run("returns juels per fee coin", func(t *testing.T) { - mockAggregator := mocks.NewAggregatorV3Interface(t) - latestRoundData := aggregator_v3_interface.LatestRoundData{Answer: big.NewInt(10000)} - mockAggregator.On("LatestRoundData", mock.Anything).Return(latestRoundData, nil) - - // Start linkEthPriceProvider. - provider := &linkEthPriceProvider{ - aggregator: mockAggregator, - timeout: time.Second / 2, - interval: time.Second, - stop: make(chan struct{}), - currentJuelsPerFeeCoin: big.NewInt(0), - lggr: logger.TestLogger(t), - } - go provider.run() - t.Cleanup(func() { close(provider.stop) }) - - // Assert correct initial price. - price, err := provider.JuelsPerFeeCoin() - require.NoError(t, err) - assert.Equal(t, int64(0), price.Int64()) - - // Wait until the price is updated. - time.Sleep(2 * time.Second) - - // Ensure the correct price is returned. - price, err = provider.JuelsPerFeeCoin() - require.NoError(t, err) - assert.Equal(t, int64(10000), price.Int64()) - }) - - t.Run("returns juels per fee coin (error updating)", func(t *testing.T) { - mockAggregator := mocks.NewAggregatorV3Interface(t) - mockAggregator.On("LatestRoundData", mock.Anything).Return(aggregator_v3_interface.LatestRoundData{}, - errors.New("could not fetch")) - - // Start linkEthPriceProvider. - provider := &linkEthPriceProvider{ - aggregator: mockAggregator, - timeout: time.Second / 2, - interval: time.Second, - stop: make(chan struct{}), - currentJuelsPerFeeCoin: big.NewInt(0), - lggr: logger.TestLogger(t), - } - go provider.run() - t.Cleanup(func() { close(provider.stop) }) - - // Assert correct initial price. - price, err := provider.JuelsPerFeeCoin() - require.NoError(t, err) - assert.Equal(t, int64(0), price.Int64()) - - // Wait until the price is updated. - time.Sleep(2 * time.Second) - - // Ensure the correct price is returned. - price, err = provider.JuelsPerFeeCoin() - require.NoError(t, err) - assert.Equal(t, int64(0), price.Int64()) - }) - - t.Run("errors out for timeout >= interval", func(t *testing.T) { - evmClient := evmclimocks.NewClient(t) - _, err := NewLinkEthPriceProvider(common.Address{}, evmClient, time.Second, time.Second, logger.TestLogger(t)) - require.Error(t, err) - require.Equal(t, "timeout must be less than interval", err.Error()) - }) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go deleted file mode 100644 index 880b8084338..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_provider.go +++ /dev/null @@ -1,42 +0,0 @@ -package reasonablegasprice - -import ( - "math/big" - "time" - - "github.com/smartcontractkit/chainlink-vrf/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" -) - -// reasonableGasPriceProvider provides an estimate for the average gas price -type reasonableGasPriceProvider struct { - estimator gas.EvmFeeEstimator - timeout time.Duration - maxGasPrice *assets.Wei - supportsDynamicFee bool -} - -var _ types.ReasonableGasPrice = (*reasonableGasPriceProvider)(nil) - -func NewReasonableGasPriceProvider( - estimator gas.EvmFeeEstimator, - timeout time.Duration, - maxGasPrice *assets.Wei, - supportsDynamicFee bool, -) types.ReasonableGasPrice { - return &reasonableGasPriceProvider{ - estimator: estimator, - timeout: timeout, - maxGasPrice: maxGasPrice, - supportsDynamicFee: supportsDynamicFee, - } -} - -// TODO: implement this function to use a gas estimator. This change can be rolled out -// to all nodes while the on-chain `useReasonableGasPrice` flag is disabled. Once reasonable -// gas prices reported by nodes become 'reasonable' the flag can be enabled. -func (r *reasonableGasPriceProvider) ReasonableGasPrice() (*big.Int, error) { - return big.NewInt(0), nil -} diff --git a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go b/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go deleted file mode 100644 index ec8b085dea8..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/reasonablegasprice/reasonable_gas_price_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package reasonablegasprice - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" -) - -func Test_ReasonableGasPrice(t *testing.T) { - t.Parallel() - - t.Run("returns reasonable gas price", func(t *testing.T) { - r := NewReasonableGasPriceProvider(nil, 1*time.Second, assets.GWei(100), true) - g, err := r.ReasonableGasPrice() - require.NoError(t, err) - - require.Equal(t, int64(0), g.Int64()) - }) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go deleted file mode 100644 index b33c749589f..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer.go +++ /dev/null @@ -1,61 +0,0 @@ -package reportserializer - -import ( - "github.com/pkg/errors" - "go.dedis.ch/kyber/v3" - - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - "github.com/smartcontractkit/chainlink-vrf/types" -) - -type reportSerializer struct { - e ocr2vrf.EthereumReportSerializer -} - -var _ types.ReportSerializer = (*reportSerializer)(nil) - -// NewReportSerializer provides a serialization component for sending byte-encoded reports on-chain. -func NewReportSerializer(encryptionGroup kyber.Group) types.ReportSerializer { - return &reportSerializer{ - e: ocr2vrf.EthereumReportSerializer{ - G: encryptionGroup, - }, - } -} - -// SerializeReport serializes an abstract report into abi-encoded bytes. -func (serializer *reportSerializer) SerializeReport(r types.AbstractReport) ([]byte, error) { - packed, err := serializer.e.SerializeReport(r) - - if err != nil { - return nil, errors.Wrap(err, "serialize report") - } - - return packed, nil -} - -// DeserializeReport deserializes a serialized byte array into a report. -func (serializer *reportSerializer) DeserializeReport(reportBytes []byte) (types.AbstractReport, error) { - // Leaving unimplemented, as serialization here is not two-way. The object that is abi-encoded on-chain is a BeaconReport, not an AbstractReport. - // So, the AbstractReport is first converted to a BeaconReport before the encoding. Converting an AbstractReport to a BeaconReport requires - // the removal of some fields, so when it is converted back to a BeaconReport and then deserialized, those fields are missing. - // Consequently, either the returned object from this function will be an abstract report - // that has had some fields removed/zeroed, or the return type will be changed to a BeaconReport, which cannot be re-serialized. - // - // Also, the need for off-chain deserialization is not currently clear. - panic("implement me") -} - -// MaxReportLength gives the max length of a report to be transmitted on-chain. -func (serializer *reportSerializer) MaxReportLength() uint { - return 150_000 // TODO: change this. -} - -// ReportLength provides the expected report length of a report. -func (serializer *reportSerializer) ReportLength(a types.AbstractReport) uint { - s, err := serializer.SerializeReport(a) - if err != nil { - return 0 - } - return uint(len(s)) -} diff --git a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go b/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go deleted file mode 100644 index 32704a55b0f..00000000000 --- a/core/services/ocr2/plugins/ocr2vrf/reportserializer/report_serializer_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package reportserializer_test - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - "github.com/smartcontractkit/chainlink-vrf/types" - - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/reportserializer" -) - -func Test_Serialize_Deserialize(t *testing.T) { - altbn128Suite := &altbn_128.PairingSuite{} - reportSerializer := reportserializer.NewReportSerializer(altbn128Suite.G1()) - - unserializedReport := types.AbstractReport{ - JuelsPerFeeCoin: big.NewInt(10), - RecentBlockHeight: 100, - RecentBlockHash: common.HexToHash("0x002"), - Outputs: []types.AbstractVRFOutput{{ - BlockHeight: 10, - ConfirmationDelay: 20, - Callbacks: []types.AbstractCostedCallbackRequest{{ - RequestID: big.NewInt(1), - NumWords: 2, - Requester: common.HexToAddress("0x03"), - Arguments: []byte{4}, - SubscriptionID: big.NewInt(5), - GasAllowance: big.NewInt(6), - Price: big.NewInt(7), - GasPrice: big.NewInt(0), - WeiPerUnitLink: big.NewInt(0), - }}, - }}, - } - r, err := reportSerializer.SerializeReport(unserializedReport) - require.NoError(t, err) - require.Equal(t, uint(len(r)), reportSerializer.ReportLength(unserializedReport)) - // TODO: Add deserialization after this point to verify. -} diff --git a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go index 4e4b912c75b..7a480dfc8e5 100644 --- a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go +++ b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/threshold/mocks/decryptor.go b/core/services/ocr2/plugins/threshold/mocks/decryptor.go index daabd6d7de9..b1afed995fc 100644 --- a/core/services/ocr2/plugins/threshold/mocks/decryptor.go +++ b/core/services/ocr2/plugins/threshold/mocks/decryptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index e39bb6d1c63..2993a67114e 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -2,7 +2,6 @@ package validate import ( "context" - "encoding/hex" "encoding/json" "errors" "fmt" @@ -20,10 +19,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/services/job" - dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" - ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/plugins" @@ -111,10 +108,6 @@ func validateSpec(ctx context.Context, tree *toml.Tree, spec job.Job, rc plugins if spec.Pipeline.Source == "" { return errors.New("no pipeline specified") } - case types.DKG: - return validateDKGSpec(spec.OCR2OracleSpec.PluginConfig) - case types.OCR2VRF: - return validateOCR2VRFSpec(spec.OCR2OracleSpec.PluginConfig) case types.OCR2Keeper: return validateOCR2KeeperSpec(spec.OCR2OracleSpec.PluginConfig) case types.Functions: @@ -312,68 +305,6 @@ func validateGenericPluginSpec(ctx context.Context, spec *job.OCR2OracleSpec, rc return plugin.ValidateConfig(ctx, spec.PluginConfig) } -func validateDKGSpec(jsonConfig job.JSONConfig) error { - if jsonConfig == nil { - return errors.New("pluginConfig is empty") - } - var pluginConfig dkgconfig.PluginConfig - err := json.Unmarshal(jsonConfig.Bytes(), &pluginConfig) - if err != nil { - return pkgerrors.Wrap(err, "error while unmarshaling plugin config") - } - err = validateHexString(pluginConfig.EncryptionPublicKey, 32) - if err != nil { - return pkgerrors.Wrap(err, "validation error for encryptedPublicKey") - } - err = validateHexString(pluginConfig.SigningPublicKey, 32) - if err != nil { - return pkgerrors.Wrap(err, "validation error for signingPublicKey") - } - err = validateHexString(pluginConfig.KeyID, 32) - if err != nil { - return pkgerrors.Wrap(err, "validation error for keyID") - } - - return nil -} - -func validateHexString(val string, expectedLengthInBytes uint) error { - decoded, err := hex.DecodeString(val) - if err != nil { - return pkgerrors.Wrapf(err, "expected hex string but received %s", val) - } - if len(decoded) != int(expectedLengthInBytes) { - return fmt.Errorf("value: %s has unexpected length. Expected %d bytes", val, expectedLengthInBytes) - } - return nil -} - -func validateOCR2VRFSpec(jsonConfig job.JSONConfig) error { - if jsonConfig == nil { - return errors.New("pluginConfig is empty") - } - var cfg ocr2vrfconfig.PluginConfig - err := json.Unmarshal(jsonConfig.Bytes(), &cfg) - if err != nil { - return pkgerrors.Wrap(err, "json unmarshal plugin config") - } - err = validateDKGSpec(job.JSONConfig{ - "encryptionPublicKey": cfg.DKGEncryptionPublicKey, - "signingPublicKey": cfg.DKGSigningPublicKey, - "keyID": cfg.DKGKeyID, - }) - if err != nil { - return err - } - if cfg.LinkEthFeedAddress == "" { - return errors.New("linkEthFeedAddress must be provided") - } - if cfg.DKGContractAddress == "" { - return errors.New("dkgContractAddress must be provided") - } - return nil -} - func validateOCR2KeeperSpec(jsonConfig job.JSONConfig) error { return nil } diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index 05a10caeaf5..b92752c647d 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -429,263 +429,6 @@ chainID = 1337 require.Contains(t, err.Error(), "no such relay blerg supported") }, }, - { - name: "valid DKG pluginConfig", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b1" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf0" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.NoError(t, err) - }, - }, - { - name: "DKG encryption key is not hex", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "frog" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b1" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf0" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "expected hex string but received frog") - require.Contains(t, err.Error(), "validation error for encryptedPublicKey") - }, - }, - { - name: "DKG encryption key is too short", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b10606" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b1" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf0" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "value: 0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b10606 has unexpected length. Expected 32 bytes") - require.Contains(t, err.Error(), "validation error for encryptedPublicKey") - }, - }, - { - name: "DKG signing key is not hex", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c" -SigningPublicKey = "frog" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf0" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "expected hex string but received frog") - require.Contains(t, err.Error(), "validation error for signingPublicKey") - }, - }, - { - name: "DKG signing key is too short", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc24" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf0" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "value: eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc24 has unexpected length. Expected 32 bytes") - require.Contains(t, err.Error(), "validation error for signingPublicKey") - }, - }, - { - name: "DKG keyID is not hex", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b1" -KeyID = "frog" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "expected hex string but received frog") - require.Contains(t, err.Error(), "validation error for keyID") - }, - }, - { - name: "DKG keyID is too long", - toml: ` -type = "offchainreporting2" -schemaVersion = 1 -name = "dkg" -externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" -maxTaskDuration = "1s" -contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" -ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" -p2pv2Bootstrappers = [ - "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" -] -relay = "evm" -pluginType = "dkg" -transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" - -[relayConfig] -chainID = 4 - -[onchainSigningStrategy] -strategyName = "single-chain" -[onchainSigningStrategy.config] -evm = "" -publicKey = "0x1234567890123456789012345678901234567890" - -[pluginConfig] -EncryptionPublicKey = "0e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c" -SigningPublicKey = "eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b1" -KeyID = "6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbaaaabc" -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - require.Contains(t, err.Error(), "value: 6f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbaaaabc has unexpected length. Expected 32 bytes") - require.Contains(t, err.Error(), "validation error for keyID") - }, - }, { name: "Generic public onchain signing strategy with no public key", toml: ` diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index 762a3d05aa3..325311352fb 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/smartcontractkit/libocr/networking/rageping" ocrnetworking "github.com/smartcontractkit/libocr/networking" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -135,7 +136,8 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { IncomingMessageBufferSize: config.IncomingMessageBufferSize(), OutgoingMessageBufferSize: config.OutgoingMessageBufferSize(), }, - MetricsRegisterer: prometheus.DefaultRegisterer, + MetricsRegisterer: prometheus.DefaultRegisterer, + LatencyMetricsServiceConfigs: rageping.DefaultConfigs(), } return peerConfig, nil diff --git a/core/services/p2p/types/mocks/peer.go b/core/services/p2p/types/mocks/peer.go index 3a2e218c170..31fb4c10d04 100644 --- a/core/services/p2p/types/mocks/peer.go +++ b/core/services/p2p/types/mocks/peer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/p2p/types/mocks/peer_wrapper.go b/core/services/p2p/types/mocks/peer_wrapper.go index cd20dc7ad94..170ab317f4c 100644 --- a/core/services/p2p/types/mocks/peer_wrapper.go +++ b/core/services/p2p/types/mocks/peer_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/p2p/types/mocks/signer.go b/core/services/p2p/types/mocks/signer.go index baacbef07bd..2e3f74a239a 100644 --- a/core/services/p2p/types/mocks/signer.go +++ b/core/services/p2p/types/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index 1c9213443fa..91653b8d142 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/orm.go b/core/services/pipeline/mocks/orm.go index 9bd5ddfbdea..387df0d41cf 100644 --- a/core/services/pipeline/mocks/orm.go +++ b/core/services/pipeline/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go index dcc15bf6fc2..cbba896ddad 100644 --- a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go +++ b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/mocks/runner.go b/core/services/pipeline/mocks/runner.go index 88d71c76c3a..cd93fbeab71 100644 --- a/core/services/pipeline/mocks/runner.go +++ b/core/services/pipeline/mocks/runner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 57c9bfd15b5..a73848f68af 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -26,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Runner --output ./mocks/ --case=underscore @@ -210,7 +209,7 @@ func (r *runner) runReaperLoop() { return } - runReaperTicker := time.NewTicker(utils.WithJitter(r.config.ReaperInterval())) + runReaperTicker := services.NewTicker(r.config.ReaperInterval()) defer runReaperTicker.Stop() for { select { @@ -218,7 +217,7 @@ func (r *runner) runReaperLoop() { return case <-runReaperTicker.C: r.runReaperWorker.WakeUp() - runReaperTicker.Reset(utils.WithJitter(r.config.ReaperInterval())) + runReaperTicker.Reset() } } } diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index f17b4aafed2..b61fa25bdc4 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -36,7 +37,8 @@ func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainCon config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) keyStore := cltest.NewKeyStore(t, db).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) + require.NoError(t, err) lggr := logger.TestLogger(t) lpOpts := logpoller.Opts{ PollPeriod: 100 * time.Millisecond, @@ -45,7 +47,8 @@ func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainCon RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, ht, lpOpts) txm, err := txmgr.NewTxm( db, diff --git a/core/services/registrysyncer/syncer_test.go b/core/services/registrysyncer/syncer_test.go index dd06e889d67..8caeec6cff3 100644 --- a/core/services/registrysyncer/syncer_test.go +++ b/core/services/registrysyncer/syncer_test.go @@ -18,7 +18,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/types" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -83,13 +85,16 @@ func newContractReaderFactory(t *testing.T, simulatedBackend *simulated.Backend) testutils.SimulatedChainID, ) db := pgtest.NewSqlxDB(t) + const finalityDepth = 2 + ht := headtracker.NewSimulatedHeadTracker(client, false, finalityDepth) lp := logpoller.NewLogPoller( logpoller.NewORM(testutils.SimulatedChainID, db, lggr), client, lggr, + ht, logpoller.Opts{ PollPeriod: 100 * time.Millisecond, - FinalityDepth: 2, + FinalityDepth: finalityDepth, BackfillBatchSize: 3, RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, diff --git a/core/services/relay/evm/cap_encoder.go b/core/services/relay/evm/cap_encoder.go index ef78cb07b48..790114e4c03 100644 --- a/core/services/relay/evm/cap_encoder.go +++ b/core/services/relay/evm/cap_encoder.go @@ -104,9 +104,9 @@ func prependMetadataFields(meta consensustypes.Metadata, userPayload []byte) ([] result = append(result, tsBytes...) // 4. DON ID (4 bytes) - if result, err = decodeAndAppend(meta.DONID, 4, result, "DONID"); err != nil { - return nil, err - } + donIDBytes := make([]byte, 4) + binary.BigEndian.PutUint32(donIDBytes, meta.DONID) + result = append(result, donIDBytes...) // 5. DON config version (4 bytes) cfgVersionBytes := make([]byte, 4) diff --git a/core/services/relay/evm/cap_encoder_test.go b/core/services/relay/evm/cap_encoder_test.go index b56d3828c42..d290a7fd2b0 100644 --- a/core/services/relay/evm/cap_encoder_test.go +++ b/core/services/relay/evm/cap_encoder_test.go @@ -20,7 +20,8 @@ var ( workflowID = "15c631d295ef5e32deb99a10ee6804bc4af1385568f9b3363f6552ac6dbb2cef" workflowName = "aabbccddeeaabbccddee" - donID = "00010203" + donID = uint32(2) + donIDHex = "00000002" executionID = "8d4e66421db647dd916d3ec28d56188c8d7dae5f808e03d03339ed2562f13bb0" workflowOwnerID = "0000000000000000000000000000000000000000" reportID = "9988" @@ -217,7 +218,7 @@ func TestEVMEncoder_InvalidIDs(t *testing.T) { } func getHexMetadata() string { - return "01" + executionID + timestampHex + donID + configVersionHex + workflowID + workflowName + workflowOwnerID + reportID + return "01" + executionID + timestampHex + donIDHex + configVersionHex + workflowID + workflowName + workflowOwnerID + reportID } func getMetadata(cid string) consensustypes.Metadata { diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 7931bfaa5d9..1f48d5ed16f 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -32,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -102,7 +103,8 @@ func TestConfigPoller(t *testing.T) { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp = logpoller.NewLogPoller(lorm, ethClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp = logpoller.NewLogPoller(lorm, ethClient, lggr, ht, lpOpts) servicetest.Run(t, lp) } diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index e6732a81cfd..0a6dea6588b 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -626,6 +626,15 @@ func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rarg ) } +func (r *Relayer) NewChainWriter(_ context.Context, config []byte) (commontypes.ChainWriter, error) { + var cfg types.ChainWriterConfig + if err := json.Unmarshal(config, &cfg); err != nil { + return nil, fmt.Errorf("failed to unmarshall chain writer config err: %s", err) + } + + return NewChainWriterService(r.lggr, r.chain.Client(), r.chain.TxManager(), r.chain.GasEstimator(), cfg) +} + func (r *Relayer) NewContractReader(chainReaderConfig []byte) (commontypes.ContractReader, error) { ctx := context.Background() cfg := &types.ChainReaderConfig{} @@ -715,6 +724,14 @@ func (r *Relayer) NewAutomationProvider(rargs commontypes.RelayArgs, pargs commo return ocr2keeperRelayer.NewOCR2KeeperProvider(rargs, pargs) } +func (r *Relayer) NewCCIPCommitProvider(_ commontypes.RelayArgs, _ commontypes.PluginArgs) (commontypes.CCIPCommitProvider, error) { + return nil, errors.New("ccip.commit is not supported for evm") +} + +func (r *Relayer) NewCCIPExecProvider(_ commontypes.RelayArgs, _ commontypes.PluginArgs) (commontypes.CCIPExecProvider, error) { + return nil, errors.New("ccip.exec is not supported for evm") +} + var _ commontypes.MedianProvider = (*medianProvider)(nil) type medianProvider struct { diff --git a/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go index b9f141b2d0b..92407809351 100644 --- a/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go +++ b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go @@ -17,6 +17,7 @@ import ( . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_tester" _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" // force binding for tx type @@ -199,7 +200,8 @@ func (it *EVMChainReaderInterfaceTester[T]) GetChainReader(t T) clcommontypes.Co RpcBatchSize: 1, KeepFinalizedBlocksDepth: 10000, } - lp := logpoller.NewLogPoller(logpoller.NewORM(it.Helper.ChainID(), db, lggr), it.client, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(it.client, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(logpoller.NewORM(it.Helper.ChainID(), db, lggr), it.client, lggr, ht, lpOpts) require.NoError(t, lp.Start(ctx)) // encode and decode the config to ensure the test covers type issues diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index dd16245464e..675bc270e4e 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" @@ -88,7 +89,8 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(lorm, ethClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(lorm, ethClient, lggr, ht, lpOpts) servicetest.Run(t, lp) configPoller, err := functions.NewFunctionsConfigPoller(pluginType, lp, lggr) require.NoError(t, err) diff --git a/core/services/relay/evm/functions/offchain_config_digester.go b/core/services/relay/evm/functions/offchain_config_digester.go index c53d07e77ca..fa8199ec0a4 100644 --- a/core/services/relay/evm/functions/offchain_config_digester.go +++ b/core/services/relay/evm/functions/offchain_config_digester.go @@ -17,7 +17,7 @@ import ( var ( _ types.OffchainConfigDigester = &functionsOffchainConfigDigester{} _ evmRelayTypes.RouteUpdateSubscriber = &functionsOffchainConfigDigester{} - FunctionsDigestPrefix = types.ConfigDigestPrefixEVM + FunctionsDigestPrefix = types.ConfigDigestPrefixEVMSimple // In order to support multiple OCR plugins with a single jobspec & OCR2Base contract, each plugin must have a unique config digest. // This is accomplished by overriding the single config digest from the contract with a unique prefix for each plugin via this custom offchain digester & config poller. ThresholdDigestPrefix = types.ConfigDigestPrefix(7) diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 9a0cfec7154..2ed934be6be 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" @@ -174,7 +175,8 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { RpcBatchSize: 2, KeepFinalizedBlocksDepth: 1000, } - lp := logpoller.NewLogPoller(lorm, ethClient, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(lorm, ethClient, lggr, ht, lpOpts) servicetest.Run(t, lp) configPoller, err := NewConfigPoller(testutils.Context(t), lggr, lp, verifierAddress, feedID) diff --git a/core/services/relay/evm/mercury/mocks/async_deleter.go b/core/services/relay/evm/mercury/mocks/async_deleter.go index 6a43c1a0568..181b9080fd5 100644 --- a/core/services/relay/evm/mercury/mocks/async_deleter.go +++ b/core/services/relay/evm/mercury/mocks/async_deleter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go index 38576174423..d7f3d8eaa0d 100644 --- a/core/services/relay/evm/mercury/persistence_manager.go +++ b/core/services/relay/evm/mercury/persistence_manager.go @@ -11,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -90,11 +89,11 @@ func (pm *PersistenceManager) runFlushDeletesLoop() { ctx, cancel := pm.stopCh.Ctx(context.Background()) defer cancel() - ticker := time.NewTicker(utils.WithJitter(pm.flushDeletesFrequency)) + ticker := services.NewTicker(pm.flushDeletesFrequency) + defer ticker.Stop() for { select { case <-ctx.Done(): - ticker.Stop() return case <-ticker.C: queuedReqs := pm.resetDeleteQueue() @@ -114,11 +113,11 @@ func (pm *PersistenceManager) runPruneLoop() { ctx, cancel := pm.stopCh.NewCtx() defer cancel() - ticker := time.NewTicker(utils.WithJitter(pm.pruneFrequency)) + ticker := services.NewTicker(pm.pruneFrequency) + defer ticker.Stop() for { select { case <-ctx.Done(): - ticker.Stop() return case <-ticker.C: func(ctx context.Context) { diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go index 1923b091531..93dc0bfc689 100644 --- a/core/services/relay/evm/mercury/queue.go +++ b/core/services/relay/evm/mercury/queue.go @@ -17,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name asyncDeleter --output ./mocks/ --case=underscore --structname=AsyncDeleter @@ -143,7 +142,7 @@ func (tq *transmitQueue) IsEmpty() bool { func (tq *transmitQueue) Start(context.Context) error { return tq.StartOnce("TransmitQueue", func() error { - t := time.NewTicker(utils.WithJitter(promInterval)) + t := services.NewTicker(promInterval) wg := new(sync.WaitGroup) chStop := make(chan struct{}) tq.stopMonitor = func() { diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index adc439e802b..58e04c5d730 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -346,13 +345,14 @@ func (m *memCache) runloop() { if m.cfg.MaxStaleAge == 0 { return } - t := time.NewTicker(utils.WithJitter(m.cfg.MaxStaleAge)) + t := services.NewTicker(m.cfg.MaxStaleAge) + defer t.Stop() for { select { case <-t.C: m.cleanup() - t.Reset(utils.WithJitter(m.cfg.MaxStaleAge)) + t.Reset() case <-m.chStop: return } diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 273589709c5..b4eb32729d3 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mocks/request_round_db.go b/core/services/relay/evm/mocks/request_round_db.go index d1aa15a3b5b..07d02af533e 100644 --- a/core/services/relay/evm/mocks/request_round_db.go +++ b/core/services/relay/evm/mocks/request_round_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go deleted file mode 100644 index f8cf7527f2c..00000000000 --- a/core/services/relay/evm/ocr2vrf.go +++ /dev/null @@ -1,178 +0,0 @@ -package evm - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" -) - -// DKGProvider provides all components needed for a DKG plugin. -type DKGProvider interface { - commontypes.Plugin -} - -// OCR2VRFProvider provides all components needed for a OCR2VRF plugin. -type OCR2VRFProvider interface { - commontypes.Plugin -} - -// OCR2VRFRelayer contains the relayer and instantiating functions for OCR2VRF providers. -type OCR2VRFRelayer interface { - NewDKGProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (DKGProvider, error) - NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (OCR2VRFProvider, error) -} - -var ( - _ OCR2VRFRelayer = (*ocr2vrfRelayer)(nil) - _ DKGProvider = (*dkgProvider)(nil) - _ OCR2VRFProvider = (*ocr2vrfProvider)(nil) -) - -// Relayer with added DKG and OCR2VRF provider functions. -type ocr2vrfRelayer struct { - chain legacyevm.Chain - lggr logger.Logger - ethKeystore keystore.Eth -} - -func NewOCR2VRFRelayer(chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2VRFRelayer { - return &ocr2vrfRelayer{ - chain: chain, - lggr: lggr, - ethKeystore: ethKeystore, - } -} - -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(ctx, r.lggr, r.chain, rargs) - if err != nil { - return nil, err - } - contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI, 0) - if err != nil { - return nil, err - } - - var pluginConfig config.PluginConfig - err = json.Unmarshal(pargs.PluginConfig, &pluginConfig) - if err != nil { - return nil, err - } - - return &dkgProvider{ - configWatcher: configWatcher, - contractTransmitter: contractTransmitter, - pluginConfig: pluginConfig, - }, nil -} - -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(ctx, r.lggr, r.chain, rargs) - if err != nil { - return nil, err - } - contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI, 0) - if err != nil { - return nil, err - } - return &ocr2vrfProvider{ - configWatcher: configWatcher, - contractTransmitter: contractTransmitter, - }, nil -} - -type dkgProvider struct { - *configWatcher - contractTransmitter ContractTransmitter - pluginConfig config.PluginConfig -} - -func (c *dkgProvider) ContractTransmitter() ocrtypes.ContractTransmitter { - return c.contractTransmitter -} - -func (c *dkgProvider) ChainReader() commontypes.ContractReader { - return nil -} - -func (c *dkgProvider) Codec() commontypes.Codec { - return nil -} - -type ocr2vrfProvider struct { - *configWatcher - contractTransmitter ContractTransmitter -} - -func (c *ocr2vrfProvider) ContractTransmitter() ocrtypes.ContractTransmitter { - return c.contractTransmitter -} - -func (c *ocr2vrfProvider) ChainReader() commontypes.ContractReader { - return nil -} - -func (c *ocr2vrfProvider) Codec() commontypes.Codec { - return nil -} - -func newOCR2VRFConfigProvider(ctx context.Context, lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { - var relayConfig types.RelayConfig - err := json.Unmarshal(rargs.RelayConfig, &relayConfig) - if err != nil { - return nil, err - } - if !common.IsHexAddress(rargs.ContractID) { - return nil, fmt.Errorf("invalid contract address '%s'", rargs.ContractID) - } - - contractAddress := common.HexToAddress(rargs.ContractID) - configPoller, err := NewConfigPoller( - ctx, - lggr.With("contractID", rargs.ContractID), - CPConfig{ - chain.Client(), - chain.LogPoller(), - contractAddress, - // TODO: Does ocr2vrf need to support config contract? DF-19182 - nil, - OCR2AggregatorLogDecoder, - }, - ) - if err != nil { - return nil, err - } - - offchainConfigDigester := evmutil.EVMOffchainConfigDigester{ - ChainID: chain.Config().EVM().ChainID().Uint64(), - ContractAddress: contractAddress, - } - - return newConfigWatcher( - lggr, - contractAddress, - offchainConfigDigester, - configPoller, - chain, - relayConfig.FromBlock, - rargs.New, - ), nil -} diff --git a/core/services/relay/evm/types/mocks/log_poller_wrapper.go b/core/services/relay/evm/types/mocks/log_poller_wrapper.go index 46a0b08d0c3..4febb453693 100644 --- a/core/services/relay/evm/types/mocks/log_poller_wrapper.go +++ b/core/services/relay/evm/types/mocks/log_poller_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/write_target.go b/core/services/relay/evm/write_target.go index 46f4f83b05b..dc1a3635330 100644 --- a/core/services/relay/evm/write_target.go +++ b/core/services/relay/evm/write_target.go @@ -69,9 +69,14 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain }, }, } - chainWriterConfig.MaxGasPrice = chain.Config().EVM().GasEstimator().PriceMax() - cw, err := NewChainWriterService(lggr.Named("ChainWriter"), chain.Client(), chain.TxManager(), chain.GasEstimator(), chainWriterConfig) + + encodedWriterConfig, err := json.Marshal(chainWriterConfig) + if err != nil { + return nil, fmt.Errorf("failed to marshal chainwriter config: %w", err) + } + + cw, err := relayer.NewChainWriter(ctx, encodedWriterConfig) if err != nil { return nil, err } diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index f616623eb89..9b627d033e8 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/s4/mocks/storage.go b/core/services/s4/mocks/storage.go index 5971b9f1ece..29344d9ebfe 100644 --- a/core/services/s4/mocks/storage.go +++ b/core/services/s4/mocks/storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/synchronization/common.go b/core/services/synchronization/common.go index 584f5b24380..1278875e331 100644 --- a/core/services/synchronization/common.go +++ b/core/services/synchronization/common.go @@ -20,7 +20,6 @@ const ( OCR2S4 TelemetryType = "ocr2-s4" OCR2Median TelemetryType = "ocr2-median" OCR3Mercury TelemetryType = "ocr3-mercury" - OCR2VRF TelemetryType = "ocr2-vrf" AutomationCustom TelemetryType = "automation-custom" OCR3Automation TelemetryType = "ocr3-automation" ) diff --git a/core/services/synchronization/mocks/telem_client.go b/core/services/synchronization/mocks/telem_client.go index 3ed4247dde8..3c19dd07bc4 100644 --- a/core/services/synchronization/mocks/telem_client.go +++ b/core/services/synchronization/mocks/telem_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/synchronization/mocks/telemetry_service.go b/core/services/synchronization/mocks/telemetry_service.go index b705d49aecd..8c6677e4be4 100644 --- a/core/services/synchronization/mocks/telemetry_service.go +++ b/core/services/synchronization/mocks/telemetry_service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/synchronization/telemetry_ingress_batch_client_test.go b/core/services/synchronization/telemetry_ingress_batch_client_test.go index c4f6417131d..964fc9b25b2 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_client_test.go @@ -45,11 +45,6 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { ContractID: "0x1", TelemType: synchronization.OCR, } - telemPayload2 := synchronization.TelemPayload{ - Telemetry: []byte("Mock telem 2"), - ContractID: "0x2", - TelemType: synchronization.OCR2VRF, - } telemPayload3 := synchronization.TelemPayload{ Telemetry: []byte("Mock telem 3"), ContractID: "0x3", @@ -58,7 +53,6 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { // Assert telemetry payloads for each contract are correctly sent to wsrpc var contractCounter1 atomic.Uint32 - var contractCounter2 atomic.Uint32 var contractCounter3 atomic.Uint32 telemClient.On("TelemBatch", mock.Anything, mock.Anything).Return(nil, nil).Run(func(args mock.Arguments) { telemBatchReq := args.Get(1).(*telemPb.TelemBatchRequest) @@ -70,13 +64,6 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { assert.Equal(t, synchronization.OCR, telemPayload1.TelemType) } } - if telemBatchReq.ContractId == "0x2" { - for _, telem := range telemBatchReq.Telemetry { - contractCounter2.Add(1) - assert.Equal(t, telemPayload2.Telemetry, telem) - assert.Equal(t, synchronization.OCR2VRF, telemPayload2.TelemType) - } - } if telemBatchReq.ContractId == "0x3" { for _, telem := range telemBatchReq.Telemetry { contractCounter3.Add(1) @@ -89,15 +76,13 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { // Send telemetry testCtx := testutils.Context(t) telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) - telemIngressClient.Send(testCtx, telemPayload2.Telemetry, telemPayload2.ContractID, telemPayload2.TelemType) telemIngressClient.Send(testCtx, telemPayload3.Telemetry, telemPayload3.ContractID, telemPayload3.TelemType) time.Sleep(sendInterval * 2) telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) - telemIngressClient.Send(testCtx, telemPayload2.Telemetry, telemPayload2.ContractID, telemPayload2.TelemType) // Wait for the telemetry to be handled g.Eventually(func() []uint32 { - return []uint32{contractCounter1.Load(), contractCounter2.Load(), contractCounter3.Load()} - }).Should(gomega.Equal([]uint32{3, 2, 1})) + return []uint32{contractCounter1.Load(), contractCounter3.Load()} + }).Should(gomega.Equal([]uint32{3, 1})) } diff --git a/core/services/vrf/mocks/aggregator_v3_interface.go b/core/services/vrf/mocks/aggregator_v3_interface.go index 65351354d7a..65bf4f11268 100644 --- a/core/services/vrf/mocks/aggregator_v3_interface.go +++ b/core/services/vrf/mocks/aggregator_v3_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index 3685e17b0ff..75cbd82d782 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index 0d62898862b..df9d5ce1aea 100644 --- a/core/services/vrf/mocks/fee_config.go +++ b/core/services/vrf/mocks/fee_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/mocks/vrf_coordinator_v2.go b/core/services/vrf/mocks/vrf_coordinator_v2.go index e8c1467e44f..79b389af234 100644 --- a/core/services/vrf/mocks/vrf_coordinator_v2.go +++ b/core/services/vrf/mocks/vrf_coordinator_v2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go index b6d3f13b8fb..3ea6f618a9c 100644 --- a/core/services/vrf/v2/listener_v2_log_listener_test.go +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" @@ -101,7 +102,8 @@ func setupVRFLogPollerListenerTH(t *testing.T, RpcBatchSize: rpcBatchSize, KeepFinalizedBlocksDepth: keepFinalizedBlocksDepth, } - lp := logpoller.NewLogPoller(o, esc, lggr, lpOpts) + ht := headtracker.NewSimulatedHeadTracker(esc, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + lp := logpoller.NewLogPoller(o, esc, lggr, ht, lpOpts) emitterAddress1, _, emitter1, err := log_emitter.DeployLogEmitter(owner, ec) require.NoError(t, err) diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index 7a3ee29f62f..7e0b334f09a 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/webhook/mocks/http_client.go b/core/services/webhook/mocks/http_client.go index 27167f235c3..4bc69d5e7e8 100644 --- a/core/services/webhook/mocks/http_client.go +++ b/core/services/webhook/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 28f37cd7c43..54d79697d82 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -83,7 +83,7 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { for _, t := range e.workflow.triggers { tg, err := e.registry.GetTrigger(ctx, t.ID) if err != nil { - e.logger.Errorf("failed to get trigger capability: %s", err) + e.logger.With(cIDKey, t.ID).Errorf("failed to get trigger capability: %s", err) // we don't immediately return here, since we want to retry all triggers // to notify the user of all errors at once. triggersInitialized = false @@ -92,7 +92,9 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { } } if !triggersInitialized { - return fmt.Errorf("failed to resolve triggers") + return &workflowError{reason: "failed to resolve triggers", labels: map[string]string{ + wIDKey: e.workflow.id, + }} } // Step 2. Walk the graph and register each step's capability to this workflow @@ -111,7 +113,12 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { err := e.initializeCapability(ctx, s) if err != nil { - return fmt.Errorf("failed to initialize capability for step %s: %w", s.Ref, err) + return &workflowError{err: err, reason: "failed to initialize capability for step", + labels: map[string]string{ + wIDKey: e.workflow.id, + sIDKey: s.ID, + sRKey: s.Ref, + }} } return nil @@ -121,6 +128,20 @@ func (e *Engine) resolveWorkflowCapabilities(ctx context.Context) error { } func (e *Engine) initializeCapability(ctx context.Context, step *step) error { + // We use varadic err here so that err can be optional, but we assume that + // its length is either 0 or 1 + newCPErr := func(reason string, errs ...error) *workflowError { + var err error + if len(errs) > 0 { + err = errs[0] + } + + return &workflowError{reason: reason, err: err, labels: map[string]string{ + wIDKey: e.workflow.id, + sIDKey: step.ID, + }} + } + // If the capability already exists, that means we've already registered it if step.capability != nil { return nil @@ -128,20 +149,22 @@ func (e *Engine) initializeCapability(ctx context.Context, step *step) error { cp, err := e.registry.Get(ctx, step.ID) if err != nil { - return fmt.Errorf("failed to get capability with ref %s: %s", step.ID, err) + return newCPErr("failed to get capability", err) } info, err := cp.Info(ctx) if err != nil { - return fmt.Errorf("failed to get info of capability with id %s: %w", step.ID, err) + return newCPErr("failed to get capability info", err) } // Special treatment for local targets - wrap into a transmission capability // If the DON is nil, this is a local target. if info.CapabilityType == capabilities.CapabilityTypeTarget && info.DON == nil { - e.logger.Debugf("wrapping capability %s in local transmission protocol", info.ID) + l := e.logger.With("capabilityID", step.ID) + l.Debug("wrapping capability in local transmission protocol") cp = transmission.NewLocalTargetCapability( e.logger, + step.ID, e.localNode, cp.(capabilities.TargetCapability), ) @@ -151,13 +174,13 @@ func (e *Engine) initializeCapability(ctx context.Context, step *step) error { // they all satisfy the `CallbackCapability` interface cc, ok := cp.(capabilities.CallbackCapability) if !ok { - return fmt.Errorf("could not coerce capability %s to CallbackCapability", step.ID) + return newCPErr("capability does not satisfy CallbackCapability") } if step.config == nil { configMap, newMapErr := values.NewMap(step.Config) if newMapErr != nil { - return fmt.Errorf("failed to convert config to values.Map: %s", newMapErr) + return newCPErr("failed to convert config to values.Map", newMapErr) } step.config = configMap } @@ -171,7 +194,7 @@ func (e *Engine) initializeCapability(ctx context.Context, step *step) error { err = cc.RegisterToWorkflow(ctx, registrationRequest) if err != nil { - return fmt.Errorf("failed to register to workflow (%+v): %w", registrationRequest, err) + return newCPErr(fmt.Sprintf("failed to register capability to workflow (%+v)", registrationRequest), err) } step.capability = cc @@ -200,7 +223,10 @@ func (e *Engine) init(ctx context.Context) { err = e.resolveWorkflowCapabilities(ctx) if err != nil { - return fmt.Errorf("failed to resolve workflow: %s", err) + return &workflowError{err: err, reason: "failed to resolve workflow capabilities", + labels: map[string]string{ + wIDKey: e.workflow.id, + }} } return nil }) @@ -214,14 +240,14 @@ func (e *Engine) init(ctx context.Context) { e.logger.Debug("capabilities resolved, resuming in-progress workflows") err := e.resumeInProgressExecutions(ctx) if err != nil { - e.logger.Errorf("failed to resume workflows: %v", err) + e.logger.Errorf("failed to resume in-progress workflows: %v", err) } e.logger.Debug("registering triggers") for idx, t := range e.workflow.triggers { err := e.registerTrigger(ctx, t, idx) if err != nil { - e.logger.Errorf("failed to register trigger: %s", err) + e.logger.With(cIDKey, t.ID).Errorf("failed to register trigger: %s", err) } } @@ -241,7 +267,7 @@ func (e *Engine) resumeInProgressExecutions(ctx context.Context) error { // TODO: paginate properly if len(wipExecutions) >= defaultLimit { - e.logger.Warnf("possible execution overflow during resumption") + e.logger.Warnf("possible execution overflow during resumption, work in progress executions: %d >= %d", len(wipExecutions), defaultLimit) } // Cache the dependents associated with a step. @@ -284,9 +310,10 @@ func generateTriggerId(workflowID string, triggerIdx int) string { // registerTrigger is used during the initialization phase to bind a trigger to this workflow func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability, triggerIdx int) error { + triggerID := generateTriggerId(e.workflow.id, triggerIdx) triggerInputs, err := values.NewMap( map[string]any{ - "triggerId": generateTriggerId(e.workflow.id, triggerIdx), + "triggerId": triggerID, }, ) if err != nil { @@ -302,22 +329,52 @@ func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability, trig triggerRegRequest := capabilities.CapabilityRequest{ Metadata: capabilities.RequestMetadata{ - WorkflowID: e.workflow.id, - WorkflowDonID: e.localNode.WorkflowDON.ID, - WorkflowName: e.workflow.name, - WorkflowOwner: e.workflow.owner, + WorkflowID: e.workflow.id, + WorkflowDonID: e.localNode.WorkflowDON.ID, + WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion, + WorkflowName: e.workflow.name, + WorkflowOwner: e.workflow.owner, }, Config: tc, Inputs: triggerInputs, } eventsCh, err := t.trigger.RegisterTrigger(ctx, triggerRegRequest) if err != nil { - return fmt.Errorf("failed to instantiate trigger %s, %s", t.ID, err) - } - + // It's confusing that t.ID is different from triggerID, but + // t.ID is the capability ID, and triggerID is the trigger ID. + // + // The capability ID is globally scoped, whereas the trigger ID + // is scoped to this workflow. + // + // For example, t.ID might be "streams-trigger:network=mainnet@1.0.0" + // and triggerID might be "wf_123_trigger_0" + return &workflowError{err: err, reason: fmt.Sprintf("failed to register trigger: %+v", triggerRegRequest), + labels: map[string]string{ + wIDKey: e.workflow.id, + cIDKey: t.ID, + tIDKey: triggerID, + }} + } + + e.wg.Add(1) go func() { - for event := range eventsCh { - e.triggerEvents <- event + defer e.wg.Done() + + for { + select { + case <-e.stopCh: + return + case event, isOpen := <-eventsCh: + if !isOpen { + return + } + + select { + case <-e.stopCh: + return + case e.triggerEvents <- event: + } + } } }() @@ -344,11 +401,11 @@ func (e *Engine) loop(ctx context.Context) { for { select { case <-ctx.Done(): - e.logger.Debugw("shutting down loop") + e.logger.Debug("shutting down loop") return case resp, isOpen := <-e.triggerEvents: if !isOpen { - e.logger.Errorf("trigger events channel is no longer open, skipping") + e.logger.Error("trigger events channel is no longer open, skipping") continue } @@ -366,13 +423,13 @@ func (e *Engine) loop(ctx context.Context) { executionID, err := generateExecutionID(e.workflow.id, te.ID) if err != nil { - e.logger.Errorf("could not generate execution ID; error %v", resp.Err) + e.logger.With(tIDKey, te.ID).Errorf("could not generate execution ID: %v", err) continue } err = e.startExecution(ctx, executionID, resp.Value) if err != nil { - e.logger.Errorf("failed to start execution: %v", err) + e.logger.With(eIDKey, executionID).Errorf("failed to start execution: %v", err) } case pendingStepRequest := <-e.pendingStepRequests: // Wait for a new worker to be available before dispatching a new one. @@ -384,7 +441,8 @@ func (e *Engine) loop(ctx context.Context) { e.wg.Add(1) go e.workerForStepRequest(ctx, pendingStepRequest) case <-t.Chan(): - e.logger.Errorf("timed out when spinning off worker for pending step request %+v", pendingStepRequest) + e.logger.With(eIDKey, pendingStepRequest.state.ExecutionID, sRKey, pendingStepRequest.stepRef). + Errorf("timed out when spinning off worker for pending step request %+v", pendingStepRequest) e.pendingStepRequests <- pendingStepRequest } t.Stop() @@ -392,7 +450,8 @@ func (e *Engine) loop(ctx context.Context) { // Executed synchronously to ensure we correctly schedule subsequent tasks. err := e.handleStepUpdate(ctx, stepUpdate) if err != nil { - e.logger.Errorf("failed to update step state: %+v, %s", stepUpdate, err) + e.logger.With(eIDKey, stepUpdate.ExecutionID, sRKey, stepUpdate.Ref). + Errorf("failed to update step state: %+v, %s", stepUpdate, err) } } } @@ -415,7 +474,7 @@ func generateExecutionID(workflowID, eventID string) (string, error) { // startExecution kicks off a new workflow execution when a trigger event is received. func (e *Engine) startExecution(ctx context.Context, executionID string, event values.Value) error { - e.logger.Debugw("executing on a trigger event", "event", event, "executionID", executionID) + e.logger.With("event", event, eIDKey, executionID).Debug("executing on a trigger event") ec := &store.WorkflowExecution{ Steps: map[string]*store.WorkflowExecutionStep{ workflows.KeywordTrigger: { @@ -457,6 +516,7 @@ func (e *Engine) handleStepUpdate(ctx context.Context, stepUpdate store.Workflow if err != nil { return err } + l := e.logger.With(eIDKey, state.ExecutionID, sRKey, stepUpdate.Ref) switch stepUpdate.Status { case store.StatusCompleted: @@ -499,7 +559,7 @@ func (e *Engine) handleStepUpdate(ctx context.Context, stepUpdate store.Workflow // We haven't completed the workflow, but should we continue? // If we've been executing for too long, let's time the workflow out and stop here. if state.CreatedAt != nil && e.clock.Since(*state.CreatedAt) > e.maxExecutionDuration { - e.logger.Infow("execution timed out", "executionID", state.ExecutionID) + l.Info("execution timed out") return e.finishExecution(ctx, state.ExecutionID, store.StatusTimeout) } @@ -509,7 +569,7 @@ func (e *Engine) handleStepUpdate(ctx context.Context, stepUpdate store.Workflow e.queueIfReady(state, sd) } case store.StatusCompletedEarlyExit: - e.logger.Infow("execution terminated early", "executionID", state.ExecutionID) + l.Info("execution terminated early") // NOTE: even though this marks the workflow as completed, any branches of the DAG // that don't depend on the step that signaled for an early exit will still complete. // This is to ensure that any side effects are executed consistently, since otherwise @@ -519,7 +579,7 @@ func (e *Engine) handleStepUpdate(ctx context.Context, stepUpdate store.Workflow return err } case store.StatusErrored: - e.logger.Infow("execution errored", "executionID", state.ExecutionID) + l.Info("execution errored") err := e.finishExecution(ctx, state.ExecutionID, store.StatusErrored) if err != nil { return err @@ -551,7 +611,8 @@ func (e *Engine) queueIfReady(state store.WorkflowExecution, step *step) { // If all dependencies are completed, enqueue the step. if !waitingOnDependencies { - e.logger.Debugw("step request enqueued", "ref", step.Ref, "state", copyState(state)) + e.logger.With(sRKey, step.Ref, eIDKey, state.ExecutionID, "state", copyState(state)). + Debug("step request enqueued") e.pendingStepRequests <- stepRequest{ state: copyState(state), stepRef: step.Ref, @@ -560,7 +621,7 @@ func (e *Engine) queueIfReady(state store.WorkflowExecution, step *step) { } func (e *Engine) finishExecution(ctx context.Context, executionID string, status string) error { - e.logger.Infow("finishing execution", "executionID", executionID, "status", status) + e.logger.With(eIDKey, executionID, "status", status).Info("finishing execution") err := e.executionStates.UpdateStatus(ctx, executionID, status) if err != nil { return err @@ -576,26 +637,26 @@ func (e *Engine) workerForStepRequest(ctx context.Context, msg stepRequest) { // Instantiate a child logger; in addition to the WorkflowID field the workflow // logger will already have, this adds the `stepRef` and `executionID` - l := e.logger.With("stepRef", msg.stepRef, "executionID", msg.state.ExecutionID) + l := e.logger.With(sRKey, msg.stepRef, eIDKey, msg.state.ExecutionID) - l.Debugw("executing on a step event") + l.Debug("executing on a step event") stepState := &store.WorkflowExecutionStep{ Outputs: store.StepOutput{}, ExecutionID: msg.state.ExecutionID, Ref: msg.stepRef, } - inputs, outputs, err := e.executeStep(ctx, l, msg) + inputs, outputs, err := e.executeStep(ctx, msg) var stepStatus string switch { case errors.Is(capabilities.ErrStopExecution, err): - l.Infow("step executed successfully with a termination") + l.Info("step executed successfully with a termination") stepStatus = store.StatusCompletedEarlyExit case err != nil: l.Errorf("error executing step request: %s", err) stepStatus = store.StatusErrored default: - l.Infow("step executed successfully", "outputs", outputs) + l.With("outputs", outputs).Info("step executed successfully") stepStatus = store.StatusCompleted } @@ -618,40 +679,48 @@ func (e *Engine) workerForStepRequest(ctx context.Context, msg stepRequest) { } // executeStep executes the referenced capability within a step and returns the result. -func (e *Engine) executeStep(ctx context.Context, l logger.Logger, msg stepRequest) (*values.Map, values.Value, error) { +func (e *Engine) executeStep(ctx context.Context, msg stepRequest) (*values.Map, values.Value, error) { step, err := e.workflow.Vertex(msg.stepRef) if err != nil { return nil, nil, err } - i, err := findAndInterpolateAllKeys(step.Inputs, msg.state) + var inputs any + if step.Inputs.OutputRef != "" { + inputs = step.Inputs.OutputRef + } else { + inputs = step.Inputs.Mapping + } + + i, err := findAndInterpolateAllKeys(inputs, msg.state) if err != nil { return nil, nil, err } - inputs, err := values.NewMap(i.(map[string]any)) + inputsMap, err := values.NewMap(i.(map[string]any)) if err != nil { return nil, nil, err } tr := capabilities.CapabilityRequest{ - Inputs: inputs, + Inputs: inputsMap, Config: step.config, Metadata: capabilities.RequestMetadata{ - WorkflowID: msg.state.WorkflowID, - WorkflowExecutionID: msg.state.ExecutionID, - WorkflowOwner: e.workflow.owner, - WorkflowName: e.workflow.name, - WorkflowDonID: e.localNode.WorkflowDON.ID, + WorkflowID: msg.state.WorkflowID, + WorkflowExecutionID: msg.state.ExecutionID, + WorkflowOwner: e.workflow.owner, + WorkflowName: e.workflow.name, + WorkflowDonID: e.localNode.WorkflowDON.ID, + WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion, }, } output, err := executeSyncAndUnwrapSingleValue(ctx, step.capability, tr) if err != nil { - return inputs, nil, err + return inputsMap, nil, err } - return inputs, output, err + return inputsMap, output, err } func (e *Engine) deregisterTrigger(ctx context.Context, t *triggerCapability, triggerIdx int) error { @@ -665,10 +734,11 @@ func (e *Engine) deregisterTrigger(ctx context.Context, t *triggerCapability, tr } deregRequest := capabilities.CapabilityRequest{ Metadata: capabilities.RequestMetadata{ - WorkflowID: e.workflow.id, - WorkflowDonID: e.localNode.WorkflowDON.ID, - WorkflowName: e.workflow.name, - WorkflowOwner: e.workflow.owner, + WorkflowID: e.workflow.id, + WorkflowDonID: e.localNode.WorkflowDON.ID, + WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion, + WorkflowName: e.workflow.name, + WorkflowOwner: e.workflow.owner, }, Inputs: triggerInputs, Config: t.config, @@ -723,7 +793,13 @@ func (e *Engine) Close() error { innerErr := s.capability.UnregisterFromWorkflow(ctx, reg) if innerErr != nil { - return fmt.Errorf("failed to unregister from workflow: %+v", reg) + return &workflowError{err: innerErr, + reason: fmt.Sprintf("failed to unregister capability from workflow: %+v", reg), + labels: map[string]string{ + wIDKey: e.workflow.id, + sIDKey: s.ID, + sRKey: s.Ref, + }} } return nil @@ -767,7 +843,11 @@ const ( func NewEngine(cfg Config) (engine *Engine, err error) { if cfg.Store == nil { - return nil, errors.New("must provide store") + return nil, &workflowError{reason: "store is nil", + labels: map[string]string{ + wIDKey: cfg.WorkflowID, + }, + } } if cfg.MaxWorkerLimit == 0 { @@ -871,3 +951,48 @@ func executeSyncAndUnwrapSingleValue(ctx context.Context, cap capabilities.Callb return l.Underlying[0], nil } + +// Logging keys +const ( + cIDKey = "capabilityID" + tIDKey = "triggerID" + wIDKey = "workflowID" + eIDKey = "executionID" + sIDKey = "stepID" + sRKey = "stepRef" +) + +type workflowError struct { + labels map[string]string + // err is the underlying error that caused this error + err error + // reason is a human-readable string that describes the error + reason string +} + +func (e *workflowError) Error() string { + // declare in reverse order so that the error message is ordered correctly + orderedLabels := []string{sRKey, sIDKey, tIDKey, cIDKey, eIDKey, wIDKey} + + errStr := "" + if e.err != nil { + if e.reason != "" { + errStr = fmt.Sprintf("%s: %v", e.reason, e.err) + } else { + errStr = e.err.Error() + } + } else { + errStr = e.reason + } + + // prefix the error with the labels + for _, label := range orderedLabels { + // This will silently ignore any labels that are not present in the map + // are we ok with this? + if value, ok := e.labels[label]; ok { + errStr = fmt.Sprintf("%s %s: %s", label, value, errStr) + } + } + + return errStr +} diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 09af6d63580..2c4129dbaf7 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -20,10 +20,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/smartcontractkit/chainlink/v2/core/services/workflows/store" ) +const testWorkflowId = "" const hardcodedWorkflow = ` triggers: - id: "mercury-trigger@1.0.0" @@ -78,6 +80,25 @@ type testHooks struct { executionFinished chan string } +func newTestDBStore(t *testing.T, clock clockwork.Clock) store.Store { + // Taken from https://github.com/smartcontractkit/chainlink/blob/d736d9e0838983a021677bc608556b3994f46690/core/services/job/orm.go#L412 + // We need to insert this row so that we dont get foreign key constraint errors + // based on the workflow_id + db := pgtest.NewSqlxDB(t) + sql := `INSERT INTO workflow_specs (workflow, workflow_id, workflow_owner, workflow_name, created_at, updated_at) + VALUES (:workflow, :workflow_id, :workflow_owner, :workflow_name, NOW(), NOW()) + RETURNING id;` + var wfSpec job.WorkflowSpec + wfSpec.Workflow = simpleWorkflow + wfSpec.WorkflowID = testWorkflowId + wfSpec.WorkflowOwner = "testowner" + wfSpec.WorkflowName = "testworkflow" + _, err := db.NamedExec(sql, wfSpec) + require.NoError(t, err) + + return store.NewDBStore(db, logger.TestLogger(t), clock) +} + // newTestEngine creates a new engine with some test defaults. func newTestEngine(t *testing.T, reg *coreCap.Registry, spec string, opts ...func(c *Config)) (*Engine, *testHooks) { peerID := p2ptypes.PeerID{} @@ -86,13 +107,14 @@ func newTestEngine(t *testing.T, reg *coreCap.Registry, spec string, opts ...fun executionFinished := make(chan string, 100) clock := clockwork.NewFakeClock() cfg := Config{ - Lggr: logger.TestLogger(t), - Registry: reg, - Spec: spec, + WorkflowID: testWorkflowId, + Lggr: logger.TestLogger(t), + Registry: reg, + Spec: spec, GetLocalNode: func(ctx context.Context) (capabilities.Node, error) { return capabilities.Node{ WorkflowDON: capabilities.DON{ - ID: "00010203", + ID: 1, }, PeerID: &peerID, }, nil @@ -110,11 +132,14 @@ func newTestEngine(t *testing.T, reg *coreCap.Registry, spec string, opts ...fun executionFinished <- weid }, clock: clock, - Store: store.NewDBStore(pgtest.NewSqlxDB(t), clock), } for _, o := range opts { o(&cfg) } + // We use the cfg clock incase they override it + if cfg.Store == nil { + cfg.Store = newTestDBStore(t, cfg.clock) + } eng, err := NewEngine(cfg) require.NoError(t, err) return eng, &testHooks{initSuccessful: initSuccessful, initFailed: initFailed, executionFinished: executionFinished} @@ -193,7 +218,6 @@ func (m *mockTriggerCapability) UnregisterTrigger(ctx context.Context, req capab } func TestEngineWithHardcodedWorkflow(t *testing.T) { - dbstore := store.NewDBStore(pgtest.NewSqlxDB(t), clockwork.NewFakeClock()) ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) @@ -223,7 +247,6 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { t, reg, hardcodedWorkflow, - func(c *Config) { c.Store = dbstore }, ) servicetest.Run(t, eng) @@ -483,8 +506,9 @@ targets: ` ) -func mockAction() (*mockCapability, values.Value) { - outputs := values.NewString("output") +func mockAction(t *testing.T) (*mockCapability, values.Value) { + outputs, err := values.NewMap(map[string]any{"output": "foo"}) + require.NoError(t, err) return newMockCapability( capabilities.MustNewCapabilityInfo( "read_chain_action@1.0.0", @@ -510,7 +534,7 @@ func TestEngine_MultiStepDependencies(t *testing.T) { require.NoError(t, reg.Add(ctx, mockConsensus())) require.NoError(t, reg.Add(ctx, mockTarget())) - action, out := mockAction() + action, out := mockAction(t) require.NoError(t, reg.Add(ctx, action)) eng, hooks := newTestEngine(t, reg, multiStepWorkflow) @@ -557,10 +581,9 @@ func TestEngine_ResumesPendingExecutions(t *testing.T) { require.NoError(t, reg.Add(ctx, mockConsensus())) require.NoError(t, reg.Add(ctx, mockTarget())) - action, _ := mockAction() + action, _ := mockAction(t) require.NoError(t, reg.Add(ctx, action)) - - dbstore := store.NewDBStore(pgtest.NewSqlxDB(t), clockwork.NewFakeClock()) + dbstore := newTestDBStore(t, clockwork.NewFakeClock()) ec := &store.WorkflowExecution{ Steps: map[string]*store.WorkflowExecutionStep{ workflows.KeywordTrigger: { @@ -572,7 +595,7 @@ func TestEngine_ResumesPendingExecutions(t *testing.T) { Ref: workflows.KeywordTrigger, }, }, - WorkflowID: "", + WorkflowID: testWorkflowId, ExecutionID: "", Status: store.StatusStarted, } @@ -610,11 +633,11 @@ func TestEngine_TimesOutOldExecutions(t *testing.T) { require.NoError(t, reg.Add(ctx, mockConsensus())) require.NoError(t, reg.Add(ctx, mockTarget())) - action, _ := mockAction() + action, _ := mockAction(t) require.NoError(t, reg.Add(ctx, action)) clock := clockwork.NewFakeClock() - dbstore := store.NewDBStore(pgtest.NewSqlxDB(t), clock) + dbstore := newTestDBStore(t, clock) ec := &store.WorkflowExecution{ Steps: map[string]*store.WorkflowExecutionStep{ workflows.KeywordTrigger: { @@ -626,7 +649,7 @@ func TestEngine_TimesOutOldExecutions(t *testing.T) { Ref: workflows.KeywordTrigger, }, }, - WorkflowID: "", + WorkflowID: testWorkflowId, ExecutionID: "", Status: store.StatusStarted, } @@ -708,7 +731,7 @@ func TestEngine_WrapsTargets(t *testing.T) { require.NoError(t, reg.Add(ctx, mockTarget())) clock := clockwork.NewFakeClock() - dbstore := store.NewDBStore(pgtest.NewSqlxDB(t), clock) + dbstore := newTestDBStore(t, clock) eng, hooks := newTestEngine( t, @@ -754,13 +777,13 @@ func TestEngine_GetsNodeInfoDuringInitialization(t *testing.T) { require.NoError(t, reg.Add(ctx, mockTarget())) clock := clockwork.NewFakeClock() - dbstore := store.NewDBStore(pgtest.NewSqlxDB(t), clock) + dbstore := newTestDBStore(t, clock) var peerID p2ptypes.PeerID node := capabilities.Node{ PeerID: &peerID, WorkflowDON: capabilities.DON{ - ID: "1", + ID: 1, }, } retryCount := 0 @@ -791,3 +814,158 @@ func TestEngine_GetsNodeInfoDuringInitialization(t *testing.T) { assert.Equal(t, node, eng.localNode) } + +const passthroughInterpolationWorkflow = ` +triggers: + - id: "mercury-trigger@1.0.0" + config: + feedIds: + - "0x1111111111111111111100000000000000000000000000000000000000000000" + - "0x2222222222222222222200000000000000000000000000000000000000000000" + - "0x3333333333333333333300000000000000000000000000000000000000000000" + +consensus: + - id: "offchain_reporting@1.0.0" + ref: "evm_median" + inputs: + observations: + - "$(trigger.outputs)" + config: + aggregation_method: "data_feeds_2_0" + aggregation_config: + "0x1111111111111111111100000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: 3600 + "0x2222222222222222222200000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: 3600 + "0x3333333333333333333300000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: 3600 + encoder: "EVM" + encoder_config: + abi: "mercury_reports bytes[]" + +targets: + - id: "write_ethereum-testnet-sepolia@1.0.0" + inputs: "$(evm_median.outputs)" + config: + address: "0x54e220867af6683aE6DcBF535B4f952cB5116510" + params: ["$(report)"] + abi: "receive(report bytes)" +` + +func TestEngine_PassthroughInterpolation(t *testing.T) { + ctx := testutils.Context(t) + reg := coreCap.NewRegistry(logger.TestLogger(t)) + + trigger, _ := mockTrigger(t) + + require.NoError(t, reg.Add(ctx, trigger)) + require.NoError(t, reg.Add(ctx, mockConsensus())) + writeID := "write_ethereum-testnet-sepolia@1.0.0" + target := newMockCapability( + capabilities.MustNewCapabilityInfo( + writeID, + capabilities.CapabilityTypeTarget, + "a write capability targeting ethereum sepolia testnet", + ), + func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + return capabilities.CapabilityResponse{ + Value: req.Inputs, + }, nil + }, + ) + require.NoError(t, reg.Add(ctx, target)) + + eng, testHooks := newTestEngine( + t, + reg, + passthroughInterpolationWorkflow, + ) + + servicetest.Run(t, eng) + + eid := getExecutionId(t, eng, testHooks) + + state, err := eng.executionStates.Get(ctx, eid) + require.NoError(t, err) + + assert.Equal(t, state.Status, store.StatusCompleted) + + // There is passthrough interpolation between the consensus and target steps, + // so the input of one should be the output of the other, exactly. + gotInputs, err := values.Unwrap(state.Steps[writeID].Inputs) + require.NoError(t, err) + + gotOutputs, err := values.Unwrap(state.Steps["evm_median"].Outputs.Value) + require.NoError(t, err) + assert.Equal(t, gotInputs, gotOutputs) +} + +func TestEngine_Error(t *testing.T) { + err := errors.New("some error") + tests := []struct { + name string + labels map[string]string + err error + reason string + want string + }{ + { + name: "Error with error and reason", + labels: map[string]string{wIDKey: "my-workflow-id"}, + err: err, + reason: "some reason", + want: "workflowID my-workflow-id: some reason: some error", + }, + { + name: "Error with error and no reason", + labels: map[string]string{eIDKey: "dd3708ac7d8dd6fa4fae0fb87b73f318a4da2526c123e159b72435e3b2fe8751"}, + err: err, + want: "executionID dd3708ac7d8dd6fa4fae0fb87b73f318a4da2526c123e159b72435e3b2fe8751: some error", + }, + { + name: "Error with no error and reason", + labels: map[string]string{cIDKey: "streams-trigger:network_eth@1.0.0"}, + reason: "some reason", + want: "capabilityID streams-trigger:network_eth@1.0.0: some reason", + }, + { + name: "Error with no error and no reason", + labels: map[string]string{tIDKey: "wf_123_trigger_456"}, + want: "triggerID wf_123_trigger_456: ", + }, + { + name: "Error with no labels", + labels: map[string]string{}, + err: err, + reason: "some reason", + want: "some reason: some error", + }, + { + name: "Multiple labels", + labels: map[string]string{ + wIDKey: "my-workflow-id", + eIDKey: "dd3708ac7d8dd6fa4fae0fb87b73f318a4da2526c123e159b72435e3b2fe8751", + cIDKey: "streams-trigger:network_eth@1.0.0", + }, + err: err, + reason: "some reason", + want: "workflowID my-workflow-id: executionID dd3708ac7d8dd6fa4fae0fb87b73f318a4da2526c123e159b72435e3b2fe8751: capabilityID streams-trigger:network_eth@1.0.0: some reason: some error", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &workflowError{ + labels: tt.labels, + err: tt.err, + reason: tt.reason, + } + if got := e.Error(); got != tt.want { + t.Errorf("err string mismatch\ngot = %v\nwant = %v", got, tt.want) + } + }) + } +} diff --git a/core/services/workflows/models_test.go b/core/services/workflows/models_test.go index 4b4747c486f..a28aeb9df01 100644 --- a/core/services/workflows/models_test.go +++ b/core/services/workflows/models_test.go @@ -214,7 +214,7 @@ targets: }, }, { - name: "non-trigger step with no dependent refs", + name: "invalid refs", yaml: ` triggers: - id: "a-trigger@1.0.0" @@ -241,7 +241,7 @@ targets: inputs: consensus_output: $(a-consensus.outputs) `, - errMsg: "all non-trigger steps must have a dependent ref", + errMsg: "invalid refs", }, { name: "duplicate edge declarations", diff --git a/core/services/workflows/store/store_db.go b/core/services/workflows/store/store_db.go index e9204efd7b1..e1d08629053 100644 --- a/core/services/workflows/store/store_db.go +++ b/core/services/workflows/store/store_db.go @@ -14,11 +14,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/values" valuespb "github.com/smartcontractkit/chainlink-common/pkg/values/pb" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) // `DBStore` is a postgres-backed // data store that persists workflow progress. type DBStore struct { + lggr logger.Logger db sqlutil.DataSource clock clockwork.Clock } @@ -197,16 +199,20 @@ func stateToStep(state *WorkflowExecutionStep) (workflowStepRow, error) { // `Add` creates the relevant workflow_execution and workflow_step entries // to persist the passed in ExecutionState. func (d *DBStore) Add(ctx context.Context, state *WorkflowExecution) error { + l := d.lggr.With("executionID", state.ExecutionID, "workflowID", state.WorkflowID, "status", state.Status) return d.transact(ctx, func(db *DBStore) error { var wid *string if state.WorkflowID != "" { wid = &state.WorkflowID } + wex := &workflowExecutionRow{ ID: state.ExecutionID, WorkflowID: wid, Status: state.Status, } + l.Debug("Adding workflow execution") + err := db.insertWorkflowExecution(ctx, wex) if err != nil { return fmt.Errorf("could not insert workflow execution %s: %w", state.ExecutionID, err) @@ -218,6 +224,7 @@ func (d *DBStore) Add(ctx context.Context, state *WorkflowExecution) error { if err != nil { return err } + l.With("stepRef", step.Ref).Debug("Adding workflow step") ws = append(ws, step) } if len(ws) > 0 { @@ -368,6 +375,6 @@ func (d *DBStore) GetUnfinished(ctx context.Context, offset, limit int) ([]Workf return states, nil } -func NewDBStore(ds sqlutil.DataSource, clock clockwork.Clock) *DBStore { - return &DBStore{db: ds, clock: clock} +func NewDBStore(ds sqlutil.DataSource, lggr logger.Logger, clock clockwork.Clock) *DBStore { + return &DBStore{db: ds, lggr: lggr.Named("WorkflowDBStore"), clock: clock} } diff --git a/core/services/workflows/store/store_db_test.go b/core/services/workflows/store/store_db_test.go index 7ae139b9435..9a98db3056f 100644 --- a/core/services/workflows/store/store_db_test.go +++ b/core/services/workflows/store/store_db_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) func randomID() string { @@ -24,9 +25,13 @@ func randomID() string { return hex.EncodeToString(b) } -func Test_StoreDB(t *testing.T) { +func newTestDBStore(t *testing.T) *DBStore { db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + return &DBStore{db: db, lggr: logger.TestLogger(t), clock: clockwork.NewFakeClock()} +} + +func Test_StoreDB(t *testing.T) { + store := newTestDBStore(t) id := randomID() es := WorkflowExecution{ @@ -58,8 +63,7 @@ func Test_StoreDB(t *testing.T) { } func Test_StoreDB_DuplicateEntry(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) id := randomID() es := WorkflowExecution{ @@ -87,8 +91,7 @@ func Test_StoreDB_DuplicateEntry(t *testing.T) { } func Test_StoreDB_UpdateStatus(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) id := randomID() es := WorkflowExecution{ @@ -122,8 +125,7 @@ func Test_StoreDB_UpdateStatus(t *testing.T) { } func Test_StoreDB_UpdateStep(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) id := randomID() stepOne := &WorkflowExecutionStep{ @@ -170,8 +172,7 @@ func Test_StoreDB_UpdateStep(t *testing.T) { } func Test_StoreDB_WorkflowStatus(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) for s := range ValidStatuses { id := randomID() @@ -200,8 +201,7 @@ func Test_StoreDB_WorkflowStatus(t *testing.T) { } func Test_StoreDB_WorkflowStepStatus(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) id := randomID() stepOne := &WorkflowExecutionStep{ @@ -234,8 +234,7 @@ func Test_StoreDB_WorkflowStepStatus(t *testing.T) { } func Test_StoreDB_GetUnfinishedSteps(t *testing.T) { - db := pgtest.NewSqlxDB(t) - store := &DBStore{db: db, clock: clockwork.NewFakeClock()} + store := newTestDBStore(t) id := randomID() stepOne := &WorkflowExecutionStep{ diff --git a/core/sessions/ldapauth/mocks/ldap_client.go b/core/sessions/ldapauth/mocks/ldap_client.go index d8fe4dbadfc..f902730d02d 100644 --- a/core/sessions/ldapauth/mocks/ldap_client.go +++ b/core/sessions/ldapauth/mocks/ldap_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/sessions/ldapauth/mocks/ldap_conn.go b/core/sessions/ldapauth/mocks/ldap_conn.go index 3116320cd99..48783feaf55 100644 --- a/core/sessions/ldapauth/mocks/ldap_conn.go +++ b/core/sessions/ldapauth/mocks/ldap_conn.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/sessions/mocks/authentication_provider.go b/core/sessions/mocks/authentication_provider.go index 3031a7c9809..69777f3e96c 100644 --- a/core/sessions/mocks/authentication_provider.go +++ b/core/sessions/mocks/authentication_provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/sessions/mocks/basic_admin_users_orm.go b/core/sessions/mocks/basic_admin_users_orm.go index b8376267c24..800f7b595a7 100644 --- a/core/sessions/mocks/basic_admin_users_orm.go +++ b/core/sessions/mocks/basic_admin_users_orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/core/store/migrate/migrations/0246_cron_spec_evm_chain_id.sql b/core/store/migrate/migrations/0246_cron_spec_evm_chain_id.sql new file mode 100644 index 00000000000..d2c0b1582e0 --- /dev/null +++ b/core/store/migrate/migrations/0246_cron_spec_evm_chain_id.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE cron_specs ADD COLUMN evm_chain_id numeric(78,0); + +-- +goose Down +ALTER TABLE cron_specs DROP COLUMN evm_chain_id; diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 949515b3357..3a1798ab5ad 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -24,7 +24,7 @@ var ( type = "cron" schemaVersion = 1 schedule = "CRON_TZ=UTC * 0 0 1 1 *" -externalJobID = "%s" +externalJobID = "%s" observationSource = """ ds [type=http method=GET url="https://chain.link/ETH-USD"]; ds_parse [type=jsonparse path="data,price"]; @@ -36,7 +36,20 @@ ds -> ds_parse -> ds_multiply; type = "cron" schemaVersion = 1 schedule = "CRON_TZ=UTC * 0 0 1 1 *" -externalJobID = "%s" +externalJobID = "%s" +observationSource = """ +ds [type=http method=GET url="https://chain.link/ETH-USD"]; +ds_parse [type=jsonparse path="data.price" separator="."]; +ds_multiply [type=multiply times=100]; +ds -> ds_parse -> ds_multiply; +""" +` + CronSpecEVMChainIDTemplate = ` +type = "cron" +schemaVersion = 1 +schedule = "CRON_TZ=UTC * 0 0 1 1 *" +externalJobID = "%s" +evmChainID = "42" observationSource = """ ds [type=http method=GET url="https://chain.link/ETH-USD"]; ds_parse [type=jsonparse path="data.price" separator="."]; @@ -62,7 +75,7 @@ type = "directrequest" schemaVersion = 1 name = "%s" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "%s" +externalJobID = "%s" evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; diff --git a/core/web/aptos_keys_controller.go b/core/web/aptos_keys_controller.go new file mode 100644 index 00000000000..5be4b815773 --- /dev/null +++ b/core/web/aptos_keys_controller.go @@ -0,0 +1,12 @@ +package web + +import ( + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" +) + +func NewAptosKeysController(app chainlink.Application) KeysController { + return NewKeysController[aptoskey.Key, presenters.AptosKeyResource](app.GetKeyStore().Aptos(), app.GetLogger(), app.GetAuditLogger(), + "aptosKey", presenters.NewAptosKeyResource, presenters.NewAptosKeyResources) +} diff --git a/core/web/aptos_keys_controller_test.go b/core/web/aptos_keys_controller_test.go new file mode 100644 index 00000000000..c5de75a5105 --- /dev/null +++ b/core/web/aptos_keys_controller_test.go @@ -0,0 +1,109 @@ +package web_test + +import ( + "fmt" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/web" + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" +) + +func TestAptosKeysController_Index_HappyPath(t *testing.T) { + t.Parallel() + + client, keyStore := setupAptosKeysControllerTests(t) + keys, _ := keyStore.Aptos().GetAll() + + response, cleanup := client.Get("/v2/keys/aptos") + t.Cleanup(cleanup) + cltest.AssertServerResponse(t, response, http.StatusOK) + + resources := []presenters.AptosKeyResource{} + err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resources) + assert.NoError(t, err) + + require.Len(t, resources, len(keys)) + + assert.Equal(t, keys[0].ID(), resources[0].ID) + assert.Equal(t, keys[0].PublicKeyStr(), resources[0].PubKey) +} + +func TestAptosKeysController_Create_HappyPath(t *testing.T) { + t.Parallel() + + app := cltest.NewApplicationEVMDisabled(t) + require.NoError(t, app.Start(testutils.Context(t))) + client := app.NewHTTPClient(nil) + keyStore := app.GetKeyStore() + + response, cleanup := client.Post("/v2/keys/aptos", nil) + t.Cleanup(cleanup) + cltest.AssertServerResponse(t, response, http.StatusOK) + + keys, _ := keyStore.Aptos().GetAll() + require.Len(t, keys, 1) + + resource := presenters.AptosKeyResource{} + err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resource) + assert.NoError(t, err) + + assert.Equal(t, keys[0].ID(), resource.ID) + assert.Equal(t, keys[0].PublicKeyStr(), resource.PubKey) + + _, err = keyStore.Aptos().Get(resource.ID) + require.NoError(t, err) +} + +func TestAptosKeysController_Delete_NonExistentAptosKeyID(t *testing.T) { + t.Parallel() + + client, _ := setupAptosKeysControllerTests(t) + + nonExistentAptosKeyID := "foobar" + response, cleanup := client.Delete("/v2/keys/aptos/" + nonExistentAptosKeyID) + t.Cleanup(cleanup) + assert.Equal(t, http.StatusNotFound, response.StatusCode) +} + +func TestAptosKeysController_Delete_HappyPath(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + client, keyStore := setupAptosKeysControllerTests(t) + + keys, _ := keyStore.Aptos().GetAll() + initialLength := len(keys) + key, _ := keyStore.Aptos().Create(ctx) + + response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/aptos/%s", key.ID())) + t.Cleanup(cleanup) + assert.Equal(t, http.StatusOK, response.StatusCode) + assert.Error(t, utils.JustError(keyStore.Aptos().Get(key.ID()))) + + keys, _ = keyStore.Aptos().GetAll() + assert.Equal(t, initialLength, len(keys)) +} + +func setupAptosKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { + t.Helper() + ctx := testutils.Context(t) + + app := cltest.NewApplication(t) + require.NoError(t, app.Start(ctx)) + require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) + aptosKeyStore := app.GetKeyStore().Aptos() + require.NotNil(t, aptosKeyStore) + require.NoError(t, aptosKeyStore.Add(ctx, cltest.DefaultAptosKey)) + + client := app.NewHTTPClient(nil) + + return client, app.GetKeyStore() +} diff --git a/core/web/assets/index.html b/core/web/assets/index.html index eb81b6d9942..e50dfc07090 100644 --- a/core/web/assets/index.html +++ b/core/web/assets/index.html @@ -1 +1 @@ -Operator UIChainlink
\ No newline at end of file +Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz index 009ac43692a..f32bc10dbc3 100644 Binary files a/core/web/assets/index.html.gz and b/core/web/assets/index.html.gz differ diff --git a/core/web/assets/main.026013f04da39527a75d.js b/core/web/assets/main.6f07a88cfc748f57e21d.js similarity index 90% rename from core/web/assets/main.026013f04da39527a75d.js rename to core/web/assets/main.6f07a88cfc748f57e21d.js index e3e27950a6f..bf6a280a999 100644 --- a/core/web/assets/main.026013f04da39527a75d.js +++ b/core/web/assets/main.6f07a88cfc748f57e21d.js @@ -171,4 +171,4 @@ object-assign */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n */ var r=n(48764),i=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}function o(e,t,n){return i(e,t,n)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=r:(a(r,t),t.Buffer=o),o.prototype=Object.create(i.prototype),a(i,o),o.from=function(e,t,n){if("number"==typeof e)throw TypeError("Argument must not be a number");return i(e,t,n)},o.alloc=function(e,t,n){if("number"!=typeof e)throw TypeError("Argument must be a number");var r=i(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},o.allocUnsafe=function(e){if("number"!=typeof e)throw TypeError("Argument must be a number");return i(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw TypeError("Argument must be a number");return r.SlowBuffer(e)}},93379(e,t,n){"use strict";var r,i,a=function(){return void 0===r&&(r=Boolean(window&&document&&document.all&&!window.atob)),r},o=(i={},function(e){if(void 0===i[e]){var t=document.querySelector(e);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(n){t=null}i[e]=t}return i[e]}),s=[];function u(e){for(var t=-1,n=0;nOW});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(39814),h=n(5977),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(37703),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e6(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e5(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n9.kG)(!!n,32),n}var rp=n(10542),rb=n(53712),rm=n(21436),rg=Object.prototype.hasOwnProperty;function rv(e,t){return void 0===t&&(t=Object.create(null)),ry(rh(t.client),e).useQuery(t)}function ry(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new rw(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var rw=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rp.J)({loading:!0,data:void 0,error:void 0,networkStatus:ru.I.loading}),this.skipStandbyResult=(0,rp.J)({loading:!1,data:void 0,error:void 0,networkStatus:ru.I.ready}),this.toQueryResultCache=new(n7.mr?WeakMap:Map),rd(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n9.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,ro.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rt((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ri.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rg.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ri.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:ru.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ri.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rb.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ra.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,t0._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n9.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rm.O)(e.errors)?new rs.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,t0._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,t0.pi)((0,t0.pi)((0,t0.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rm.O)(e.errors)&&(t.error=new rs.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:ru.I.refetch}),this.observable.refetch())},e}();function r_(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return rv(iH,e)},iz=function(){var e=ij(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=i$({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(iR,null):o?l.createElement(iD,{error:o}):i?l.createElement(iI,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iG=n(67932),iW=n(8126),iK="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iV(e){if(iq())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iq(){return("undefined"==typeof Intl?"undefined":iK(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iZ="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iX=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iZ(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iZ(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i1=iQ;var i0=new i1;function i2(e,t){if(!iq())return function(e){return e.toString()};var n=i4(e),r=JSON.stringify(t),i=i0.get(String(n),r)||i0.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i3={};function i4(e){var t=e.toString();return i3[t]?i3[t]:i3[t]=iV(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i5(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i9(e)}function i9(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var i7=n(54087),ae=n.n(i7);function at(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)aa(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=ae()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){ae().cancel(this.scheduledTick)}};function ai(e){var t=an(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function aa(e,t){ai(e),as(t,e),ao(t,e)}function ao(e,t){var n=au(e,t);e.splice(n,0,t)}function as(e,t){var n=e.indexOf(t);e.splice(n,1)}function au(e,t){var n=t.nextUpdateTime;return at(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var ac=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),al=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(ac).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),af=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ap(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ah(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iW.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iW.Z(y)},[y]);t=(0,l.useMemo)(function(){return i5(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ad(u,2),l=c[0],f=c[1];return f=o?ag:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ad(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ad(M,2),A=O[0],L=O[1],C=ad((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ar.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ad(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i2(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,af({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,af({},f,{verboseDate:I?R:void 0}),j):j}ap.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:al,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ap.defaultProps={locales:[],component:av,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ap=l.memo(ap);let ab=ap;var am,ag=31536e9;function av(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ah(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",af({},a,{dateTime:o,title:r?n:void 0}),i)}av.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var ay=n(30381),aw=n.n(ay),a_=n(31657);function aE(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function aS(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new rs.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ri.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ri.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,t0.pi)({reset:c},a)]}var os=n(59067),ou=n(28428),oc=n(11186),ol=n(78513);function of(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var od=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:of({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},oh=(0,b.withStyles)(od)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ii.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),op=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},ob=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},om=(0,b.withStyles)(od)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function og(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sq=sV;function sZ(e,t){var n=this.__data__,r=sH(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sX=sZ;function sJ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cC}let cD=cI;var cN="[object Arguments]",cP="[object Array]",cR="[object Boolean]",cj="[object Date]",cF="[object Error]",cY="[object Function]",cB="[object Map]",cU="[object Number]",cH="[object Object]",c$="[object RegExp]",cz="[object Set]",cG="[object String]",cW="[object WeakMap]",cK="[object ArrayBuffer]",cV="[object DataView]",cq="[object Float64Array]",cZ="[object Int8Array]",cX="[object Int16Array]",cJ="[object Int32Array]",cQ="[object Uint8Array]",c1="[object Uint8ClampedArray]",c0="[object Uint16Array]",c2="[object Uint32Array]",c3={};function c4(e){return eD(e)&&cD(e.length)&&!!c3[eC(e)]}c3["[object Float32Array]"]=c3[cq]=c3[cZ]=c3[cX]=c3[cJ]=c3[cQ]=c3[c1]=c3[c0]=c3[c2]=!0,c3[cN]=c3[cP]=c3[cK]=c3[cR]=c3[cV]=c3[cj]=c3[cF]=c3[cY]=c3[cB]=c3[cU]=c3[cH]=c3[c$]=c3[cz]=c3[cG]=c3[cW]=!1;let c6=c4;function c5(e){return function(t){return e(t)}}let c8=c5;var c9=n(79730),c7=c9.Z&&c9.Z.isTypedArray,le=c7?c8(c7):c6;let lt=le;var ln=Object.prototype.hasOwnProperty;function lr(e,t){var n=cx(e),r=!n&&cS(e),i=!n&&!r&&(0,cT.Z)(e),a=!n&&!r&&!i&<(e),o=n||r||i||a,s=o?cb(e.length,String):[],u=s.length;for(var c in e)(t||ln.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cL(c,u)))&&s.push(c);return s}let li=lr;var la=Object.prototype;function lo(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||la)}let ls=lo;var lu=sT(Object.keys,Object);let lc=lu;var ll=Object.prototype.hasOwnProperty;function lf(e){if(!ls(e))return lc(e);var t=[];for(var n in Object(e))ll.call(e,n)&&"constructor"!=n&&t.push(n);return t}let ld=lf;function lh(e){return null!=e&&cD(e.length)&&!ur(e)}let lp=lh;function lb(e){return lp(e)?li(e):ld(e)}let lm=lb;function lg(e,t){return e&&ch(t,lm(t),e)}let lv=lg;function ly(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let lw=ly;var l_=Object.prototype.hasOwnProperty;function lE(e){if(!ed(e))return lw(e);var t=ls(e),n=[];for(var r in e)"constructor"==r&&(t||!l_.call(e,r))||n.push(r);return n}let lS=lE;function lk(e){return lp(e)?li(e,!0):lS(e)}let lx=lk;function lT(e,t){return e&&ch(t,lx(t),e)}let lM=lT;var lO=n(42896);function lA(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hu(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hc=function(e){return Array.isArray(e)&&0===e.length},hl=function(e){return"function"==typeof e},hf=function(e){return null!==e&&"object"==typeof e},hd=function(e){return String(Math.floor(Number(e)))===e},hh=function(e){return"[object String]"===Object.prototype.toString.call(e)},hp=function(e){return 0===l.Children.count(e)},hb=function(e){return hf(e)&&hl(e.then)};function hm(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hv(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hm(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hg(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sk.all([t,n,r],{arrayMerge:hL})})},[h.validate,h.validationSchema,T,S,k]),O=hN(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sd()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sd()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hb(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sd()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sd()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hS,E({type:"SET_ERRORS",payload:h.initialErrors||hS}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sd()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hk,E({type:"SET_TOUCHED",payload:h.initialTouched||hk}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sd()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hN(function(e){if(y.current[e]&&hl(y.current[e].validate)){var t=hm(_.values,e),n=y.current[e].validate(t);return hb(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hN(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hN(function(e,t){var r=hl(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hN(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hg(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hh(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hI(hm(_.values,r),l,c):d?hC(f):c}r&&j(r,i)},[j,_.values]),Y=hN(function(e){if(hh(e))return function(t){return F(t,e)};F(e)}),B=hN(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hN(function(e){if(hh(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hl(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hN(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hN(function(e){e&&e.preventDefault&&hl(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hl(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hN(function(){return f(_.values,V)}),Z=hN(function(e){e&&e.preventDefault&&hl(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hl(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hm(_.values,e),error:hm(_.errors,e),touched:!!hm(_.touched,e),initialValue:hm(p.current,e),initialTouched:!!hm(m.current,e),initialError:hm(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hf(e),n=t?e.name:e,r=hm(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sd()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hl(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ha({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hT(e){var t=hx(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(hw,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hl(r)?r(t):hp(r)?null:l.Children.only(r):null)}function hM(e){var t={};if(e.inner){if(0===e.inner.length)return hg(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hm(t,o.path)||(t=hg(t,o.path,o.message))}}return t}function hO(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hA(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hA(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sR(e)?hA(e):""!==e?e:void 0}):sR(e[r])?t[r]=hA(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hL(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sk(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sk(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hC(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hI(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hD="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hN(e){var t=(0,l.useRef)(e);return hD(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ha({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hg(n.values,a,e(hm(n.values,a))),u=r?i(hm(n.errors,a)):void 0,c=t?o(hm(n.touched,a)):void 0;return hc(u)&&(u=void 0),hc(c)&&(c=void 0),ha({},n,{values:s,errors:r?hg(n.errors,a,u):n.errors,touched:t?hg(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hU(t),[hi(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hj(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},function(t){return hY(t,e,null)},function(t){return hY(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hu(n)),n.pop=n.pop.bind(hu(n)),n}ho(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sd()(hm(e.formik.values,e.name),hm(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hU(n):[];return t||(t=r[e]),hl(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hs(t.formik,["validate","validationSchema"]),s=ha({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hp(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var hH=n(24802),h$=n(71209),hz=n(91750),hG=n(11970),hW=n(4689),hK=n(67598),hV=function(){return(hV=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hZ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hq(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hq(e,["disabled","field","form","onBlur","helperText"]),d=hm(u,i.name),h=hm(s,i.name)&&!!d;return hV(hV({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hX(e){var t=e.children,n=hq(e,["children"]);return(0,l.createElement)(iw.Z,hV({},hZ(n)),t)}function hJ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hq(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hq(e,["disabled","field","form","type","onBlur"]);return hV(hV({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function hQ(e){return(0,l.createElement)(hH.Z,hV({},hJ(e)))}function h1(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hq(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hq(e,["disabled","field","form","type","onBlur"]);return hV(hV({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h0(e){return(0,l.createElement)(h$.Z,hV({},h1(e)))}function h2(e){var t=e.Label,n=hq(e,["Label"]);return(0,l.createElement)(hz.Z,hV({control:(0,l.createElement)(h$.Z,hV({},h1(n)))},t))}function h3(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hq(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hq(e,["disabled","field","form","onBlur"]);return hV(hV({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h4(e){return(0,l.createElement)(hG.default,hV({},h3(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hq(t,["onBlur"]),i=(e.form,e.onBlur),a=hq(e,["field","form","onBlur"]);return hV(hV({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h5(e){return(0,l.createElement)(hW.Z,hV({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hq(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hq(e,["disabled","field","form","onBlur"]);return hV(hV({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h9(e){return(0,l.createElement)(hK.default,hV({},h8(e)))}hX.displayName="FormikMaterialUITextField",hQ.displayName="FormikMaterialUISwitch",h0.displayName="FormikMaterialUICheckbox",h2.displayName="FormikMaterialUICheckboxWithLabel",h4.displayName="FormikMaterialUISelect",h5.displayName="FormikMaterialUIRadioGroup",h9.displayName="FormikMaterialUIInputBase";try{a=Map}catch(h7){}try{o=Set}catch(pe){}function pt(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pn);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pt(e[i],t,n)}return r}return e}function pn(e){return pt(e,[],[])}let pr=Object.prototype.toString,pi=Error.prototype.toString,pa=RegExp.prototype.toString,po="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",ps=/^Symbol\((.*)\)(.*)$/;function pu(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pc(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pu(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return po.call(e).replace(ps,"Symbol($1)");let r=pr.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pi.call(e)+"]":"RegExp"===r?pa.call(e):null}function pl(e,t){let n=pc(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pc(this[e],t);return null!==r?r:n},2)}let pf={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pl(n,!0)}\``+(i?` (cast from the value \`${pl(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},pd={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},ph={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pp={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pb={isValue:"${path} field must be ${value}"},pm={noUnknown:"${path} field has unspecified keys: ${unknown}"},pg={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pf,string:pd,number:ph,date:pp,object:pm,array:pg,boolean:pb});var pv=n(18721),py=n.n(pv);let pw=e=>e&&e.__isYupSchema__;class p_{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!py()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!pw(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pE=p_;function pS(e){return null==e?[]:[].concat(e)}function pk(){return(pk=Object.assign||function(e){for(var t=1;tpl(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pS(e).forEach(e=>{pT.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pT)}}let pM=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pO(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pM(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pT(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pR(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pP(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pD.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pL()(pN({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pT(pT.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pN({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pT.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pT.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pD.prototype.__isYupRef=!0;let pj=e=>e.substr(0,e.length-1).substr(1);function pF(e,t,n,r=n){let i,a,o;return t?((0,pC.forEach)(t,(s,u,c)=>{let l=u?pj(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pY{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pD.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pD.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pY;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pB(){return(pB=Object.assign||function(e){for(var t=1;t{this.typeError(pf.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pB({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pB({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pn(pB({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pB({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pB({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pl(e),a=pl(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". attempted value: ${i} -`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pB({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pO({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pO({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pB({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pB({},t,{value:e}))._validate(e,pB({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pT.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pT.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pn(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pf.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pf.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pf.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pR(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pS(e).map(e=>new pD(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pE(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pR({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pf.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pR({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pf.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pR({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let pH of(pU.prototype.__isYupSchema__=!0,["validate","validateSync"]))pU.prototype[`${pH}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pF(this,e,t,n.context);return a[pH](r&&r[i],pB({},n,{parent:r,path:e}))};for(let p$ of["equals","is"])pU.prototype[p$]=pU.prototype.oneOf;for(let pz of["not","nope"])pU.prototype[pz]=pU.prototype.notOneOf;pU.prototype.optional=pU.prototype.notRequired;let pG=pU;function pW(){return new pG}pW.prototype=pG.prototype;let pK=e=>null==e;function pV(){return new pq}class pq extends pU{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pb.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pK(e)||!0===e})}isFalse(e=pb.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pK(e)||!1===e})}}pV.prototype=pq.prototype;let pZ=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pX=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pJ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,pQ=e=>pK(e)||e===e.trim(),p1=({}).toString();function p0(){return new p2}class p2 extends pU{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p1?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=pd.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pK(t)||t.length===this.resolve(e)}})}min(e,t=pd.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t.length>=this.resolve(e)}})}max(e,t=pd.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pK(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||pd.matches,params:{regex:e},test:t=>pK(t)||""===t&&n||-1!==t.search(e)})}email(e=pd.email){return this.matches(pZ,{name:"email",message:e,excludeEmptyString:!0})}url(e=pd.url){return this.matches(pX,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=pd.uuid){return this.matches(pJ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=pd.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:pQ})}lowercase(e=pd.lowercase){return this.transform(e=>pK(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pK(e)||e===e.toLowerCase()})}uppercase(e=pd.uppercase){return this.transform(e=>pK(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pK(e)||e===e.toUpperCase()})}}p0.prototype=p2.prototype;let p3=e=>e!=+e;function p4(){return new p6}class p6 extends pU{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p3(e)}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t>=this.resolve(e)}})}max(e,t=ph.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pK(t)||t<=this.resolve(e)}})}lessThan(e,t=ph.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pK(t)||tthis.resolve(e)}})}positive(e=ph.positive){return this.moreThan(0,e)}negative(e=ph.negative){return this.lessThan(0,e)}integer(e=ph.integer){return this.test({name:"integer",message:e,test:e=>pK(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pK(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pK(t)?t:Math[e](t))}}p4.prototype=p6.prototype;var p5=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p5.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p9=new Date(""),p7=e=>"[object Date]"===Object.prototype.toString.call(e);function be(){return new bt}class bt extends pU{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p9:new Date(e))})})}_typeCheck(e){return p7(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pD.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pp.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pK(e)||e>=this.resolve(n)}})}max(e,t=pp.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pK(e)||e<=this.resolve(n)}})}}bt.INVALID_DATE=p9,be.prototype=bt.prototype,be.INVALID_DATE=p9;var bn=n(11865),br=n.n(bn),bi=n(68929),ba=n.n(bi),bo=n(67523),bs=n.n(bo),bu=n(94633),bc=n.n(bu);function bl(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pC.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(py()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pD.isRef(o)&&o.isSibling?i(o.path,a):pw(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bc().array(r,n).reverse()}function bf(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bd(e){return(t,n)=>bf(e,t)-bf(e,n)}function bh(){return(bh=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bb(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bm=bd([]);class bg extends pU{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bm,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bp(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bh({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=py()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pT.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bp(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bh({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pO({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bh({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pU&&i instanceof pU&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bd(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bl(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pC.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return py()(i,e)&&(a=bh({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pm.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bb(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pm.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bs()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(ba())}snakeCase(){return this.transformKeys(br())}constantCase(){return this.transformKeys(e=>br()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pL()(this.fields,e=>e.describe()),e}}function bv(e){return new bg(e)}function by(){return(by=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,by({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pT.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pO({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!pw(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pl(e));return t.innerType=e,t}length(e,t=pg.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pK(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pg.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pg.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pK(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}bw.prototype=b_.prototype;var bE=bv().shape({name:p0().required("Required"),url:p0().required("Required")}),bS=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hT,{initialValues:t,validationSchema:bE,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hR,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hP,{component:hX,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hP,{component:hX,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hP,{component:hX,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hP,{component:hX,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bk=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Edit Bridge",action:l.createElement(aA.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aW.Z,null,l.createElement(bS,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},mc=n(76023);function ml(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mB(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mZ={};function mX(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mZ[t]||(mZ[t]=mq(e)),mZ[t]}function mJ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mX(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mK({},e,n[t])},t)}function mQ(e){return e.join(" ")}function m1(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m0({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m0(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m1(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mK({},s,{className:mQ(m)||void 0,style:mJ(s.className,Object.assign({},s.style,i),n)})}else d=mK({},s,{className:mQ(s.className)});var g=h(t.children);return l.createElement(c,(0,mV.Z)({key:o},d),g)}}let m2=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m3=/\n/g;function m4(e){return e.match(m3)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m5(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m9(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function m7(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mK({},i,"function"==typeof e?e(t):e)}function ge(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=m7(r,n,i);t.unshift(m9(n,h))}return f&l&&(d.style=mK({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gt(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return ge({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=m7(s,t,o);e.unshift(m9(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m4(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(ge({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=ge({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gu=n(98695),gc=n.n(gu);let gl=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gf=go(gc(),gs);gf.supportedLanguages=gl;let gd=gf;var gh=n(64566);function gp(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gb(){var e=gp(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gb=function(){return e},e}var gm=n0(gb()),gg=function(e){var t=e.children;return l.createElement(ir.Z,null,l.createElement(r7.default,{component:"th",scope:"row",colSpan:3},t))},gv=function(){return l.createElement(gg,null,"...")},gy=function(e){var t=e.children;return l.createElement(gg,null,t)},gw=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gy,null,i);if(t)return l.createElement(gv,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mP.Z,{defaultExpanded:o},l.createElement(mR.Z,{expandIcon:l.createElement(gh.Z,null)},a),l.createElement(mj.Z,{style:s},l.createElement(gd,{language:"toml",style:gs},n))))},g_=function(){var e=rv(gm,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"TOML Configuration"}),l.createElement(gw,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"TOML Configuration"}),l.createElement(gw,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gw,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gE=n(34823),gS=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gk=(0,b.withStyles)(gS)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gE.N,A.wU);return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r9.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ir.Z,null,l.createElement(r7.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gx=function(){return l.createElement(ig,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(g_,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gk,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mN,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mE,null))))))},gT=function(){return l.createElement(gx,null)},gM=function(){return l.createElement(gT,null)},gO=n(44431),gA=1e18,gL=function(e){return new gO.BigNumber(e).dividedBy(gA).toFixed(8)},gC=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sl.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aW.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(op,{title:"Address"}),l.createElement(ob,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(op,{title:"Native Token Balance"}),l.createElement(ob,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(op,{title:"LINK Balance"}),l.createElement(ob,{value:e.linkBalance?gL(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gB.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,{className:r.footer},l.createElement(aA.Z,{href:"/runs",component:tz},"View More"))))))});function vt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vn(){var e=vt(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vn=function(){return e},e}var vr=5,vi=n0(vn(),g9),va=function(){var e=rv(vi,{variables:{offset:0,limit:vr},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(ve,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vr})},vo=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vs=(0,b.withStyles)(vo)(function(e){var t=e.classes,n=(0,A.v9)(gE.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ii.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vu=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vc=(0,b.withStyles)(vu)(function(e){var t=e.classes,n=e.job;return l.createElement(ir.Z,null,l.createElement(r7.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ih,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aO,{tooltip:!0},n.createdAt))))))});function vl(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vf(){var e=vl(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vf=function(){return e},e}var vd=n0(vf()),vh=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vp=(0,b.withStyles)(vh)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r9.Z,null,l.createElement(g$,{visible:o}),l.createElement(gz,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gU,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vc,{job:e,key:t})}))))});function vb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vm(){var e=vb(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vm=function(){return e},e}var vg=5,vv=n0(vm(),vd),vy=function(){var e=rv(vv,{variables:{offset:0,limit:vg},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vp,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vw=function(){return l.createElement(ig,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(va,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gY,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vy,null))))),l.createElement(vs,null))},v_=function(){return l.createElement(vw,null)},vE=function(){return l.createElement(v_,null)},vS=n(87239),vk=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vx=n(5022),vT=n(78718),vM=n.n(vT);function vO(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ir.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(r7.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(r7.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aO,{tooltip:!0},e.createdAt))),l.createElement(r7.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yh(t,e.status))},e.status.toLowerCase())))})))}),yb=n(16839),ym=n.n(yb);function yg(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=ym().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yv=n(94164),yy=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yw=n(73343),y_=n(3379),yE=n.n(y_);function yS(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yv.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yw.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yy,{data:e}))}))};function yL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyY&&l.createElement("div",{className:t.runDetails},l.createElement(aA.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yF,{observationSource:n.observationSource})))});function yH(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vx.parse(e),!0}catch(t){return!1}})}),wW=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hT,{initialValues:t,validationSchema:wG,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hR,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wK=n(50109),wV="persistSpec";function wq(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wK.t8(wV,n),{toml:n}):{toml:wK.U2(wV)||""}}var wZ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wq({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wK.t8("".concat(wV),t),n&&n(t)};return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"New Job"}),l.createElement(aW.Z,null,l.createElement(wW,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wX(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _M(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(_W,e)},_V=function(){var e=_K({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_U,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_q=function(e){var t=e.csaKey;return l.createElement(ir.Z,{hover:!0},l.createElement(r7.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_x,{data:t.publicKey}))))};function _Z(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _X(){var e=_Z(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _X=function(){return e},e}var _J=n0(_X()),_Q=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r5.Z,null,l.createElement(sl.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ok.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(ie.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,null,"Public Key"))),l.createElement(r9.Z,null,l.createElement(g$,{visible:o}),l.createElement(gz,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gU,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_q,{csaKey:e,key:t})}))))};function _1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(EM,e)};function EA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(EJ,e)},E3=function(){return oo(EQ)},E4=function(){return oo(E1)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return rv(E0,e)};function E5(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(SK,e)};function Sq(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kV(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kq=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kK(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kW(kz({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r5.Z,null,l.createElement(aW.Z,null,l.createElement(kH,{object:n})))};function kZ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kX(e){for(var t=1;t0&&l.createElement(kr,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kq,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kN,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k5(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k5(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k9=n0(k8(),k4),k7=function(){var e=rv(k9,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(iR,null);if(r)return l.createElement(iD,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oa,null);default:return null}};function xe(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xt(){var e=xe(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xt=function(){return e},e}var xn=n0(xt()),xr=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iy,null,"Job Runs")),t&&l.createElement(iR,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(yp,{runs:o}),l.createElement(it.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xa(){var e=xi(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xa=function(){return e},e}var xo=n0(xa(),xn),xs=function(){var e=ij(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=rv(xo,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iD,{error:o}):l.createElement(xr,{loading:a,data:i,page:t,pageSize:n})},xu=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xs,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(k7,null)))},xc=bv().shape({name:p0().required("Required"),uri:p0().required("Required"),publicKey:p0().required("Required")}),xl=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hT,{initialValues:t,validationSchema:xc,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hR,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ok.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xf=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Edit Feeds Manager"}),l.createElement(aW.Z,null,l.createElement(xl,{initialValues:r,onSubmit:n})))))};function xd(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xh(){var e=xd(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xh=function(){return e},e}var xp=n0(xh()),xb=function(){return rv(xp)};function xm(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function xF(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function xY(e,t){return xD(e)||xP(e,t)||xB(e,t)||xR()}function xB(e,t){if(e){if("string"==typeof e)return xI(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return xI(e,t)}}var xU=function(e){return"SN_MAIN"===e||"SN_SEPOLIA"===e},xH=bv().shape({chainID:p0().required("Required"),chainType:p0().required("Required"),accountAddr:p0().required("Required"),accountAddrPubKey:p0().nullable(),adminAddr:p0().required("Required"),ocr1Multiaddr:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&t},then:p0().required("Required").nullable()}).nullable(),ocr1P2PPeerID:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr1KeyBundleID:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2Multiaddr:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&t},then:p0().required("Required").nullable()}).nullable(),ocr2P2PPeerID:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2KeyBundleID:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2CommitPluginEnabled:pV().required("Required"),ocr2ExecutePluginEnabled:pV().required("Required"),ocr2MedianPluginEnabled:pV().required("Required"),ocr2MercuryPluginEnabled:pV().required("Required"),ocr2ForwarderAddress:p0().nullable()}),x$=function(e){return(0,b.createStyles)({supportedJobOptionsPaper:{padding:2*e.spacing.unit}})},xz=function(e){var t=e.chainAccounts,n=xj(e,["chainAccounts"]),r=h_(),i=r.values,a=i.chainID,o=i.accountAddr,s=r.setFieldValue,u=xY(l.useState(!1),2),c=u[0],f=u[1],d=l.useRef();l.useEffect(function(){d.current=a},[a]),l.useEffect(function(){a!==d.current&&(s(n.name,""),f(!1))},[a,s,n.name]);var h=function(e){var t=e.target.value;"custom"===t?(f(!0),s(n.name,"")):(f(!1),s(n.name,t))};return l.createElement(l.Fragment,null,!xU(a)&&l.createElement(hP,xN({},n,{select:!0,value:c?"custom":o,onChange:h}),t.map(function(e){return l.createElement(tE.default,{key:e.address,value:e.address},e.address)})),xU(a)&&l.createElement(hP,{component:hX,id:"accountAddr",name:"accountAddr",label:"Enter your account address",inputProps:{"data-testid":"customAccountAddr-input"},helperText:"The account address used for this chain",required:!0,fullWidth:!0}),xU(a)&&l.createElement("div",null,l.createElement(hP,{component:hX,id:"accountAddrPubKey",name:"accountAddrPubKey",label:"Account Address Public Key",required:!0,fullWidth:!0,helperText:"The public key for your account address",FormHelperTextProps:{"data-testid":"accountAddrPubKey-helper-text"}})))},xG=(0,b.withStyles)(x$)(function(e){var t=e.classes,n=e.editing,r=void 0!==n&&n,i=e.innerRef,a=e.initialValues,o=e.onSubmit,s=e.chainIDs,u=void 0===s?[]:s,c=e.accounts,f=void 0===c?[]:c,h=e.p2pKeys,p=void 0===h?[]:h,b=e.ocrKeys,m=void 0===b?[]:b,g=e.ocr2Keys,v=void 0===g?[]:g,y=e.showSubmit,w=void 0!==y&&y;return l.createElement(hT,{innerRef:i,initialValues:a,validationSchema:xH,onSubmit:o},function(e){var n=e.values,i=f.filter(function(e){return e.chain.id==n.chainID&&!e.isDisabled});return l.createElement(hR,{"data-testid":"feeds-manager-form",id:"chain-configuration-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"chainType",name:"chainType",label:"Chain Type",select:!0,required:!0,fullWidth:!0,disabled:!0},l.createElement(tE.default,{key:"EVM",value:"EVM"},"EVM"))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"chainID",name:"chainID",label:"Chain ID",required:!0,fullWidth:!0,select:!0,disabled:r,inputProps:{"data-testid":"chainID-input"},FormHelperTextProps:{"data-testid":"chainID-helper-text"}},u.map(function(e){return l.createElement(tE.default,{key:e,value:e},e)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(xz,{component:hX,id:"accountAddr",name:"accountAddr",label:"Account Address",inputProps:{"data-testid":"accountAddr-input"},required:!0,fullWidth:!0,select:!0,helperText:"The account address used for this chain",chainAccounts:i,FormHelperTextProps:{"data-testid":"accountAddr-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"adminAddr",name:"adminAddr",label:"Admin Address",required:!0,fullWidth:!0,helperText:"The address used for LINK payments",FormHelperTextProps:{"data-testid":"adminAddr-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,null,"Supported Job Types")),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"fluxMonitorEnabled",type:"checkbox",Label:{label:"Flux Monitor"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr1Enabled",type:"checkbox",Label:{label:"OCR"}}),n.ocr1Enabled&&l.createElement(ii.default,{className:t.supportedJobOptionsPaper},l.createElement(d.Z,{container:!0,spacing:8},l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr1IsBootstrap",type:"checkbox",Label:{label:"Is this node running as a bootstrap peer?"}})),n.ocr1IsBootstrap?l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"ocr1Multiaddr",name:"ocr1Multiaddr",label:"Multiaddr",required:!0,fullWidth:!0,helperText:"The OCR Multiaddr which oracles use to query for network information",FormHelperTextProps:{"data-testid":"ocr1Multiaddr-helper-text"}})):l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr1P2PPeerID",name:"ocr1P2PPeerID",label:"Peer ID",select:!0,required:!0,fullWidth:!0,helperText:"The Peer ID used for this chain",FormHelperTextProps:{"data-testid":"ocr1P2PPeerID-helper-text"}},p.map(function(e){return l.createElement(tE.default,{key:e.peerID,value:e.peerID},e.peerID)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr1KeyBundleID",name:"ocr1KeyBundleID",label:"Key Bundle ID",select:!0,required:!0,fullWidth:!0,helperText:"The OCR Key Bundle ID used for this chain",FormHelperTextProps:{"data-testid":"ocr1KeyBundleID-helper-text"}},m.map(function(e){return l.createElement(tE.default,{key:e.id,value:e.id},e.id)})))))))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr2Enabled",type:"checkbox",Label:{label:"OCR2"}}),n.ocr2Enabled&&l.createElement(ii.default,{className:t.supportedJobOptionsPaper},l.createElement(d.Z,{container:!0,spacing:8},l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr2IsBootstrap",type:"checkbox",Label:{label:"Is this node running as a bootstrap peer?"}})),n.ocr2IsBootstrap?l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"ocr2Multiaddr",name:"ocr2Multiaddr",label:"Multiaddr",required:!0,fullWidth:!0,helperText:"The OCR2 Multiaddr which oracles use to query for network information",FormHelperTextProps:{"data-testid":"ocr2Multiaddr-helper-text"}})):l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr2P2PPeerID",name:"ocr2P2PPeerID",label:"Peer ID",select:!0,required:!0,fullWidth:!0,helperText:"The Peer ID used for this chain",FormHelperTextProps:{"data-testid":"ocr2P2PPeerID-helper-text"}},p.map(function(e){return l.createElement(tE.default,{key:e.peerID,value:e.peerID},e.peerID)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr2KeyBundleID",name:"ocr2KeyBundleID",label:"Key Bundle ID",select:!0,required:!0,fullWidth:!0,helperText:"The OCR2 Key Bundle ID used for this chain",FormHelperTextProps:{"data-testid":"ocr2KeyBundleID-helper-text"}},v.filter(function(e){return n.chainType===e.chainType}).map(function(e){return l.createElement(tE.default,{key:e.id,value:e.id},e.id)}))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,null,"Supported Plugins")),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2CommitPluginEnabled",type:"checkbox",Label:{label:"Commit"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2ExecutePluginEnabled",type:"checkbox",Label:{label:"Execute"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2RebalancerPluginEnabled",type:"checkbox",Label:{label:"Rebalancer"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2MedianPluginEnabled",type:"checkbox",Label:{label:"Median"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2MercuryPluginEnabled",type:"checkbox",Label:{label:"Mercury"}})),l.createElement(d.Z,{item:!0,xs:12,md:12},l.createElement(hP,{component:hX,id:"ocr2ForwarderAddress",name:"ocr2ForwarderAddress",label:"Forwarder Address (optional)",fullWidth:!0,helperText:"The forwarder address from the Operator Forwarder Contract",FormHelperTextProps:{"data-testid":"ocr2ForwarderAddress-helper-text"}}))))))),w&&l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",size:"large"},"Submit"))))})}),xW=function(e){var t=e.onClose,n=e.open,r=e.onSubmit,i=l.useRef(),a=i$({fetchPolicy:"network-only"}).data,o=_K({fetchPolicy:"cache-and-network"}).data,s=SV({fetchPolicy:"cache-and-network"}).data,u=EO({fetchPolicy:"cache-and-network"}).data,c=E2({fetchPolicy:"cache-and-network"}).data,f={chainID:"",chainType:"EVM",accountAddr:"",adminAddr:"",accountAddrPubKey:"",fluxMonitorEnabled:!1,ocr1Enabled:!1,ocr1IsBootstrap:!1,ocr1Multiaddr:"",ocr1P2PPeerID:"",ocr1KeyBundleID:"",ocr2Enabled:!1,ocr2IsBootstrap:!1,ocr2Multiaddr:"",ocr2P2PPeerID:"",ocr2KeyBundleID:"",ocr2CommitPluginEnabled:!1,ocr2ExecutePluginEnabled:!1,ocr2MedianPluginEnabled:!1,ocr2MercuryPluginEnabled:!1,ocr2RebalancerPluginEnabled:!1,ocr2ForwarderAddress:""},d=a?a.chains.results.map(function(e){return e.id}):[],h=o?o.ethKeys.results:[],p=s?s.p2pKeys.results:[],b=u?u.ocrKeyBundles.results:[],m=c?c.ocr2KeyBundles.results:[];return l.createElement(aD.Z,{onClose:t,open:n,disableBackdropClick:!0},l.createElement(oO.Z,{disableTypography:!0},l.createElement(x.default,{variant:"body2"},"New Supported Chain")),l.createElement(oT.Z,null,l.createElement(xG,{innerRef:i,initialValues:f,onSubmit:r,chainIDs:d,accounts:h,p2pKeys:p,ocrKeys:b,ocr2Keys:m})),l.createElement(ox.Z,null,l.createElement(ok.default,{onClick:t},"Cancel"),l.createElement(ok.default,{color:"primary",type:"submit",form:"chain-configuration-form",variant:"contained"},"Submit")))},xK=function(e){var t=e.cfg,n=e.onClose,r=e.open,i=e.onSubmit,a=l.useRef(),o=i$({fetchPolicy:"network-only"}).data,s=_K({fetchPolicy:"cache-and-network"}).data,u=SV({fetchPolicy:"cache-and-network"}).data,c=EO({fetchPolicy:"cache-and-network"}).data,f=E2({fetchPolicy:"cache-and-network"}).data;if(!t)return null;var d={chainID:t.chainID,chainType:"EVM",accountAddr:t.accountAddr,adminAddr:t.adminAddr,accountAddrPubKey:t.accountAddrPubKey,fluxMonitorEnabled:t.fluxMonitorJobConfig.enabled,ocr1Enabled:t.ocr1JobConfig.enabled,ocr1IsBootstrap:t.ocr1JobConfig.isBootstrap,ocr1Multiaddr:t.ocr1JobConfig.multiaddr,ocr1P2PPeerID:t.ocr1JobConfig.p2pPeerID,ocr1KeyBundleID:t.ocr1JobConfig.keyBundleID,ocr2Enabled:t.ocr2JobConfig.enabled,ocr2IsBootstrap:t.ocr2JobConfig.isBootstrap,ocr2Multiaddr:t.ocr2JobConfig.multiaddr,ocr2P2PPeerID:t.ocr2JobConfig.p2pPeerID,ocr2KeyBundleID:t.ocr2JobConfig.keyBundleID,ocr2CommitPluginEnabled:t.ocr2JobConfig.plugins.commit,ocr2ExecutePluginEnabled:t.ocr2JobConfig.plugins.execute,ocr2MedianPluginEnabled:t.ocr2JobConfig.plugins.median,ocr2MercuryPluginEnabled:t.ocr2JobConfig.plugins.mercury,ocr2RebalancerPluginEnabled:t.ocr2JobConfig.plugins.rebalancer,ocr2ForwarderAddress:t.ocr2JobConfig.forwarderAddress},h=o?o.chains.results.map(function(e){return e.id}):[],p=s?s.ethKeys.results:[],b=u?u.p2pKeys.results:[],m=c?c.ocrKeyBundles.results:[],g=f?f.ocr2KeyBundles.results:[];return l.createElement(aD.Z,{onClose:n,open:r,disableBackdropClick:!0},l.createElement(oO.Z,{disableTypography:!0},l.createElement(x.default,{variant:"body2"},"Edit Supported Chain")),l.createElement(oT.Z,null,l.createElement(xG,{innerRef:a,initialValues:d,onSubmit:i,chainIDs:h,accounts:p,p2pKeys:b,ocrKeys:m,ocr2Keys:g,editing:!0})),l.createElement(ox.Z,null,l.createElement(ok.default,{onClick:n},"Cancel"),l.createElement(ok.default,{color:"primary",type:"submit",form:"chain-configuration-form",variant:"contained"},"Submit")))};function xV(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xq(){var e=xV(["\n fragment FeedsManager_ChainConfigFields on FeedsManagerChainConfig {\n id\n chainID\n chainType\n accountAddr\n adminAddr\n accountAddrPubKey\n fluxMonitorJobConfig {\n enabled\n }\n ocr1JobConfig {\n enabled\n isBootstrap\n multiaddr\n p2pPeerID\n keyBundleID\n }\n ocr2JobConfig {\n enabled\n isBootstrap\n multiaddr\n forwarderAddress\n p2pPeerID\n keyBundleID\n plugins {\n commit\n execute\n median\n mercury\n rebalancer\n }\n }\n }\n"]);return xq=function(){return e},e}function xZ(){var e=xV(["\n ","\n fragment FeedsManagerFields on FeedsManager {\n id\n name\n uri\n publicKey\n isConnectionActive\n chainConfigs {\n ...FeedsManager_ChainConfigFields\n }\n }\n"]);return xZ=function(){return e},e}function xX(){var e=xV(["\n fragment FeedsManager_JobProposalsFields on JobProposal {\n id\n name\n externalJobID\n remoteUUID\n status\n pendingUpdate\n latestSpec {\n createdAt\n version\n }\n }\n"]);return xX=function(){return e},e}function xJ(){var e=xV(["\n ","\n ","\n fragment FeedsManagerPayload_ResultsFields on FeedsManager {\n ...FeedsManagerFields\n jobProposals {\n ...FeedsManager_JobProposalsFields\n }\n }\n"]);return xJ=function(){return e},e}function xQ(){var e=xV(["\n ","\n query FetchFeedManagersWithProposals {\n feedsManagers {\n results {\n ...FeedsManagerPayload_ResultsFields\n }\n }\n }\n"]);return xQ=function(){return e},e}var x1=n0(xq()),x0=n0(xZ(),x1),x2=n0(xX()),x3=n0(xJ(),x0,x2),x4=n0(xQ(),x3),x6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return rv(x4,e)};function x5(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TZ,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TJ={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TQ=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Register Feeds Manager"}),l.createElement(aW.Z,null,l.createElement(xl,{initialValues:TJ,onSubmit:t})))))};function T1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return ME(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mP.Z,{defaultExpanded:0===n,key:n},l.createElement(mR.Z,{expandIcon:l.createElement(gh.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Es.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aO,{tooltip:!0},e.createdAt)))),l.createElement(mj.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ok.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gd,{language:"toml",style:gs,"data-testid":"codeblock"},e.definition)))}),l.createElement(oC,{open:null!=c,title:c?MM[c.action].title:"",body:c?MM[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Md,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MA(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ML(){var e=MA(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ML=function(){return e},e}var MC=n0(ML(),Mx),MI=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iy,null,"Job Proposal #",a.id))),l.createElement(Mo,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(Tq,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(MO,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(37703),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(37703),a=n(5977),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(39814),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(37703),a=n(97779),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ru,ZT:()=>i,_T:()=>o,ev:()=>c,mG:()=>s,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n}function s(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||(n=Promise))(function(n,a){function o(e){try{u(r.next(e))}catch(t){a(t)}}function s(e){try{u(r.throw(e))}catch(t){a(t)}}function u(e){e.done?n(e.value):i(e.value).then(o,s)}u((r=r.apply(e,t||[])).next())})}function u(e,t){var n,r,i,a,o={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return a={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(e){return function(t){return u([e,t])}}function u(a){if(n)throw TypeError("Generator is already executing.");for(;o;)try{if(n=1,r&&(i=2&a[0]?r.return:a[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,a[1])).done)return i;switch(r=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return o.label++,{value:a[1],done:!1};case 5:o.label++,r=a[1],a=[0];continue;case 7:a=o.ops.pop(),o.trys.pop();continue;default:if(!(i=(i=o.trys).length>0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]r})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}e.exports=i,e.exports.__esModule=!0,e.exports.default=e.exports},7071(e){function t(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},94993(e,t,n){var r=n(18698).default,i=n(66115);function a(e,t){if(t&&("object"===r(t)||"function"==typeof t))return t;if(void 0!==t)throw TypeError("Derived constructors may only return object or undefined");return i(e)}e.exports=a,e.exports.__esModule=!0,e.exports.default=e.exports},6015(e){function t(n,r){return e.exports=t=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},e.exports.__esModule=!0,e.exports.default=e.exports,t(n,r)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},861(e,t,n){var r=n(63405),i=n(79498),a=n(86116),o=n(42281);function s(e){return r(e)||i(e)||a(e)||o()}e.exports=s,e.exports.__esModule=!0,e.exports.default=e.exports},18698(e){function t(n){return e.exports=t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.__esModule=!0,e.exports.default=e.exports,t(n)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},86116(e,t,n){var r=n(73897);function i(e,t){if(e){if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}}e.exports=i,e.exports.__esModule=!0,e.exports.default=e.exports},1644(e,t,n){"use strict";var r,i;function a(e){return!!e&&e<7}n.d(t,{I:()=>r,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(70655);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(70655),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},4942(e,t,n){"use strict";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}n.d(t,{Z:()=>r})},87462(e,t,n){"use strict";function r(){return(r=Object.assign?Object.assign.bind():function(e){for(var t=1;tr})},51721(e,t,n){"use strict";function r(e,t){return(r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e})(e,t)}function i(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>i})},63366(e,t,n){"use strict";function r(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}n.d(t,{Z:()=>r})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(37703),p=__webpack_require__(97779),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t6(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t8("(",t6(e.variableDefinitions,", "),")"),i=t6(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t6([t,t6([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t8(" = ",r)+t8(" ",t6(i," "))},SelectionSet:function(e){return t5(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t8("",t,": ")+n,s=o+t8("(",t6(r,", "),")");return s.length>t2&&(s=o+t8("(\n",t9(t6(r,"\n")),"\n)")),t6([s,t6(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t8(" ",t6(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t6(["...",t8("on ",t),t6(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t8("(",t6(r,", "),")")," ")+"on ".concat(n," ").concat(t8("",t6(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t6(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t6(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t8("(",t6(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t6(["schema",t6(t," "),t5(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t6(["scalar",e.name,t6(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["type",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t8("(\n",t9(t6(n,"\n")),"\n)"):t8("(",t6(n,", "),")"))+": "+r+t8(" ",t6(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t6([t+": "+n,t8("= ",r),t6(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["interface",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t6(["union",t,t6(n," "),r&&0!==r.length?"= "+t6(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t6(["enum",t,t6(n," "),t5(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t6([e.name,t6(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t6(["input",t,t6(n," "),t5(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t8("(\n",t9(t6(n,"\n")),"\n)"):t8("(",t6(n,", "),")"))+(r?" repeatable":"")+" on "+t6(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t6(["extend schema",t6(t," "),t5(n)]," ")},ScalarTypeExtension:function(e){var t;return t6(["extend scalar",e.name,t6(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["extend type",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["extend interface",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t6(["extend union",t,t6(n," "),r&&0!==r.length?"= "+t6(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t6(["extend enum",t,t6(n," "),t5(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t6(["extend input",t,t6(n," "),t5(r)]," ")}};function t4(e){return function(t){return t6([t.description,e(t)],"\n")}}function t6(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t5(e){return t8("{\n",t9(t6(e,"\n")),"\n}")}function t8(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t9(e){return t8(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n6(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n5(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n8(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n9(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e8(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n9(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n9(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r6=new(t_.mr?WeakMap:Map);function r5(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r6.set(e,(r6.get(e)+1)%1e15),n.apply(this,arguments)})}function r8(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r9=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r6.has(n)||(r6.set(n,0),r5(n,"evict"),r5(n,"modify"),r5(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r8(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r8(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r6.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r6.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e9(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r9(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r9&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n5(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r9(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e9(e6(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e8(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e9(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i5(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i8(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i9(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i5(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i6=[];function i5(e,t){var n=e.map;return n.has(t)||n.set(t,i6.pop()||{map:new Map}),n.get(t)}function i8(e,t){if(e===t||!t||i9(t))return e;if(!e||i9(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i8(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i8(t.map.get(n),e.map.get(n)))})}return a}function i9(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i9(r)&&(i6.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","StandardCapabilitiesSpec","VRFSpec","WebhookSpec","WorkflowSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pB({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pO({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pO({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pB({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pB({},t,{value:e}))._validate(e,pB({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pT.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pT.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pn(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pf.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pf.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pf.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pR(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pS(e).map(e=>new pD(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pE(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pR({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pf.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pR({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pf.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pR({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let pH of(pU.prototype.__isYupSchema__=!0,["validate","validateSync"]))pU.prototype[`${pH}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pF(this,e,t,n.context);return a[pH](r&&r[i],pB({},n,{parent:r,path:e}))};for(let p$ of["equals","is"])pU.prototype[p$]=pU.prototype.oneOf;for(let pz of["not","nope"])pU.prototype[pz]=pU.prototype.notOneOf;pU.prototype.optional=pU.prototype.notRequired;let pG=pU;function pW(){return new pG}pW.prototype=pG.prototype;let pK=e=>null==e;function pV(){return new pq}class pq extends pU{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pb.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pK(e)||!0===e})}isFalse(e=pb.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pK(e)||!1===e})}}pV.prototype=pq.prototype;let pZ=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pX=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pJ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,pQ=e=>pK(e)||e===e.trim(),p1=({}).toString();function p0(){return new p2}class p2 extends pU{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p1?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=pd.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pK(t)||t.length===this.resolve(e)}})}min(e,t=pd.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t.length>=this.resolve(e)}})}max(e,t=pd.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pK(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||pd.matches,params:{regex:e},test:t=>pK(t)||""===t&&n||-1!==t.search(e)})}email(e=pd.email){return this.matches(pZ,{name:"email",message:e,excludeEmptyString:!0})}url(e=pd.url){return this.matches(pX,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=pd.uuid){return this.matches(pJ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=pd.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:pQ})}lowercase(e=pd.lowercase){return this.transform(e=>pK(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pK(e)||e===e.toLowerCase()})}uppercase(e=pd.uppercase){return this.transform(e=>pK(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pK(e)||e===e.toUpperCase()})}}p0.prototype=p2.prototype;let p3=e=>e!=+e;function p4(){return new p6}class p6 extends pU{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p3(e)}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t>=this.resolve(e)}})}max(e,t=ph.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pK(t)||t<=this.resolve(e)}})}lessThan(e,t=ph.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pK(t)||tthis.resolve(e)}})}positive(e=ph.positive){return this.moreThan(0,e)}negative(e=ph.negative){return this.lessThan(0,e)}integer(e=ph.integer){return this.test({name:"integer",message:e,test:e=>pK(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pK(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pK(t)?t:Math[e](t))}}p4.prototype=p6.prototype;var p5=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p5.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p9=new Date(""),p7=e=>"[object Date]"===Object.prototype.toString.call(e);function be(){return new bt}class bt extends pU{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p9:new Date(e))})})}_typeCheck(e){return p7(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pD.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pp.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pK(e)||e>=this.resolve(n)}})}max(e,t=pp.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pK(e)||e<=this.resolve(n)}})}}bt.INVALID_DATE=p9,be.prototype=bt.prototype,be.INVALID_DATE=p9;var bn=n(11865),br=n.n(bn),bi=n(68929),ba=n.n(bi),bo=n(67523),bs=n.n(bo),bu=n(94633),bc=n.n(bu);function bl(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pC.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(py()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pD.isRef(o)&&o.isSibling?i(o.path,a):pw(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bc().array(r,n).reverse()}function bf(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bd(e){return(t,n)=>bf(e,t)-bf(e,n)}function bh(){return(bh=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bb(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bm=bd([]);class bg extends pU{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bm,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bp(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bh({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=py()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pT.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bp(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bh({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pO({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bh({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pU&&i instanceof pU&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bd(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bl(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pC.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return py()(i,e)&&(a=bh({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pm.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bb(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pm.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bs()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(ba())}snakeCase(){return this.transformKeys(br())}constantCase(){return this.transformKeys(e=>br()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pL()(this.fields,e=>e.describe()),e}}function bv(e){return new bg(e)}function by(){return(by=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,by({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pT.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pO({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!pw(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pl(e));return t.innerType=e,t}length(e,t=pg.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pK(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pg.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pK(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pg.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pK(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}bw.prototype=b_.prototype;var bE=bv().shape({name:p0().required("Required"),url:p0().required("Required")}),bS=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hT,{initialValues:t,validationSchema:bE,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hR,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hP,{component:hX,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hP,{component:hX,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hP,{component:hX,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hP,{component:hX,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bk=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Edit Bridge",action:l.createElement(aA.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aW.Z,null,l.createElement(bS,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},mc=n(76023);function ml(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mB(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mZ={};function mX(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mZ[t]||(mZ[t]=mq(e)),mZ[t]}function mJ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mX(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mK({},e,n[t])},t)}function mQ(e){return e.join(" ")}function m1(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m0({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m0(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m1(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mK({},s,{className:mQ(m)||void 0,style:mJ(s.className,Object.assign({},s.style,i),n)})}else d=mK({},s,{className:mQ(s.className)});var g=h(t.children);return l.createElement(c,(0,mV.Z)({key:o},d),g)}}let m2=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m3=/\n/g;function m4(e){return e.match(m3)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m5(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m9(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function m7(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mK({},i,"function"==typeof e?e(t):e)}function ge(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=m7(r,n,i);t.unshift(m9(n,h))}return f&l&&(d.style=mK({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gt(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return ge({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=m7(s,t,o);e.unshift(m9(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m4(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(ge({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=ge({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gu=n(98695),gc=n.n(gu);let gl=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gf=go(gc(),gs);gf.supportedLanguages=gl;let gd=gf;var gh=n(64566);function gp(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gb(){var e=gp(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gb=function(){return e},e}var gm=n0(gb()),gg=function(e){var t=e.children;return l.createElement(ir.Z,null,l.createElement(r7.default,{component:"th",scope:"row",colSpan:3},t))},gv=function(){return l.createElement(gg,null,"...")},gy=function(e){var t=e.children;return l.createElement(gg,null,t)},gw=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gy,null,i);if(t)return l.createElement(gv,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mP.Z,{defaultExpanded:o},l.createElement(mR.Z,{expandIcon:l.createElement(gh.Z,null)},a),l.createElement(mj.Z,{style:s},l.createElement(gd,{language:"toml",style:gs},n))))},g_=function(){var e=rv(gm,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"TOML Configuration"}),l.createElement(gw,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"TOML Configuration"}),l.createElement(gw,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gw,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gE=n(34823),gS=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gk=(0,b.withStyles)(gS)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gE.N,A.wU);return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r9.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ir.Z,null,l.createElement(r7.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gx=function(){return l.createElement(ig,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(g_,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gk,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mN,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mE,null))))))},gT=function(){return l.createElement(gx,null)},gM=function(){return l.createElement(gT,null)},gO=n(44431),gA=1e18,gL=function(e){return new gO.BigNumber(e).dividedBy(gA).toFixed(8)},gC=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sl.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aW.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(op,{title:"Address"}),l.createElement(ob,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(op,{title:"Native Token Balance"}),l.createElement(ob,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(op,{title:"LINK Balance"}),l.createElement(ob,{value:e.linkBalance?gL(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gB.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,{className:r.footer},l.createElement(aA.Z,{href:"/runs",component:tz},"View More"))))))});function vt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vn(){var e=vt(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vn=function(){return e},e}var vr=5,vi=n0(vn(),g9),va=function(){var e=rv(vi,{variables:{offset:0,limit:vr},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(ve,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vr})},vo=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vs=(0,b.withStyles)(vo)(function(e){var t=e.classes,n=(0,A.v9)(gE.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ii.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vu=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vc=(0,b.withStyles)(vu)(function(e){var t=e.classes,n=e.job;return l.createElement(ir.Z,null,l.createElement(r7.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ih,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aO,{tooltip:!0},n.createdAt))))))});function vl(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vf(){var e=vl(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vf=function(){return e},e}var vd=n0(vf()),vh=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vp=(0,b.withStyles)(vh)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r9.Z,null,l.createElement(g$,{visible:o}),l.createElement(gz,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gU,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vc,{job:e,key:t})}))))});function vb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vm(){var e=vb(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vm=function(){return e},e}var vg=5,vv=n0(vm(),vd),vy=function(){var e=rv(vv,{variables:{offset:0,limit:vg},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vp,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vw=function(){return l.createElement(ig,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(va,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gY,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vy,null))))),l.createElement(vs,null))},v_=function(){return l.createElement(vw,null)},vE=function(){return l.createElement(v_,null)},vS=n(87239),vk=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vx=n(5022),vT=n(78718),vM=n.n(vT);function vO(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ir.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(r7.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(r7.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aO,{tooltip:!0},e.createdAt))),l.createElement(r7.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yh(t,e.status))},e.status.toLowerCase())))})))}),yb=n(16839),ym=n.n(yb);function yg(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=ym().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yv=n(94164),yy=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yw=n(73343),y_=n(3379),yE=n.n(y_);function yS(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yv.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yw.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yy,{data:e}))}))};function yL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyY&&l.createElement("div",{className:t.runDetails},l.createElement(aA.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yF,{observationSource:n.observationSource})))});function yH(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vx.parse(e),!0}catch(t){return!1}})}),wW=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hT,{initialValues:t,validationSchema:wG,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hR,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wK=n(50109),wV="persistSpec";function wq(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wK.t8(wV,n),{toml:n}):{toml:wK.U2(wV)||""}}var wZ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wq({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wK.t8("".concat(wV),t),n&&n(t)};return l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"New Job"}),l.createElement(aW.Z,null,l.createElement(wW,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wX(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _M(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(_W,e)},_V=function(){var e=_K({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_U,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_q=function(e){var t=e.csaKey;return l.createElement(ir.Z,{hover:!0},l.createElement(r7.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_x,{data:t.publicKey}))))};function _Z(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _X(){var e=_Z(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _X=function(){return e},e}var _J=n0(_X()),_Q=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r5.Z,null,l.createElement(sl.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ok.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(ie.Z,null,l.createElement(ir.Z,null,l.createElement(r7.default,null,"Public Key"))),l.createElement(r9.Z,null,l.createElement(g$,{visible:o}),l.createElement(gz,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gU,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_q,{csaKey:e,key:t})}))))};function _1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(EM,e)};function EA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(EJ,e)},E3=function(){return oo(EQ)},E4=function(){return oo(E1)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return rv(E0,e)};function E5(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return rv(SK,e)};function Sq(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kV(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kq=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kK(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kW(kz({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r5.Z,null,l.createElement(aW.Z,null,l.createElement(kH,{object:n})))};function kZ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kX(e){for(var t=1;t0&&l.createElement(kr,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kq,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kN,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k5(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k5(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k9=n0(k8(),k4),k7=function(){var e=rv(k9,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(iR,null);if(r)return l.createElement(iD,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oa,null);default:return null}};function xe(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xt(){var e=xe(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xt=function(){return e},e}var xn=n0(xt()),xr=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iy,null,"Job Runs")),t&&l.createElement(iR,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r5.Z,null,l.createElement(yp,{runs:o}),l.createElement(it.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xa(){var e=xi(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xa=function(){return e},e}var xo=n0(xa(),xn),xs=function(){var e=ij(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=rv(xo,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iD,{error:o}):l.createElement(xr,{loading:a,data:i,page:t,pageSize:n})},xu=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xs,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(k7,null)))},xc=bv().shape({name:p0().required("Required"),uri:p0().required("Required"),publicKey:p0().required("Required")}),xl=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hT,{initialValues:t,validationSchema:xc,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hR,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ok.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xf=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Edit Feeds Manager"}),l.createElement(aW.Z,null,l.createElement(xl,{initialValues:r,onSubmit:n})))))};function xd(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xh(){var e=xd(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xh=function(){return e},e}var xp=n0(xh()),xb=function(){return rv(xp)};function xm(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function xF(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}function xY(e,t){return xD(e)||xP(e,t)||xB(e,t)||xR()}function xB(e,t){if(e){if("string"==typeof e)return xI(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return xI(e,t)}}var xU=function(e){return"SN_MAIN"===e||"SN_SEPOLIA"===e},xH=bv().shape({chainID:p0().required("Required"),chainType:p0().required("Required"),accountAddr:p0().required("Required"),accountAddrPubKey:p0().nullable(),adminAddr:p0().required("Required"),ocr1Multiaddr:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&t},then:p0().required("Required").nullable()}).nullable(),ocr1P2PPeerID:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr1KeyBundleID:p0().when(["ocr1Enabled","ocr1IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2Multiaddr:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&t},then:p0().required("Required").nullable()}).nullable(),ocr2P2PPeerID:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2KeyBundleID:p0().when(["ocr2Enabled","ocr2IsBootstrap"],{is:function(e,t){return e&&!t},then:p0().required("Required").nullable()}).nullable(),ocr2CommitPluginEnabled:pV().required("Required"),ocr2ExecutePluginEnabled:pV().required("Required"),ocr2MedianPluginEnabled:pV().required("Required"),ocr2MercuryPluginEnabled:pV().required("Required"),ocr2ForwarderAddress:p0().nullable()}),x$=function(e){return(0,b.createStyles)({supportedJobOptionsPaper:{padding:2*e.spacing.unit}})},xz=function(e){var t=e.chainAccounts,n=xj(e,["chainAccounts"]),r=h_(),i=r.values,a=i.chainID,o=i.accountAddr,s=r.setFieldValue,u=xY(l.useState(!1),2),c=u[0],f=u[1],d=l.useRef();l.useEffect(function(){d.current=a},[a]),l.useEffect(function(){a!==d.current&&(s(n.name,""),f(!1))},[a,s,n.name]);var h=function(e){var t=e.target.value;"custom"===t?(f(!0),s(n.name,"")):(f(!1),s(n.name,t))};return l.createElement(l.Fragment,null,!xU(a)&&l.createElement(hP,xN({},n,{select:!0,value:c?"custom":o,onChange:h}),t.map(function(e){return l.createElement(tE.default,{key:e.address,value:e.address},e.address)})),xU(a)&&l.createElement(hP,{component:hX,id:"accountAddr",name:"accountAddr",label:"Enter your account address",inputProps:{"data-testid":"customAccountAddr-input"},helperText:"The account address used for this chain",required:!0,fullWidth:!0}),xU(a)&&l.createElement("div",null,l.createElement(hP,{component:hX,id:"accountAddrPubKey",name:"accountAddrPubKey",label:"Account Address Public Key",required:!0,fullWidth:!0,helperText:"The public key for your account address",FormHelperTextProps:{"data-testid":"accountAddrPubKey-helper-text"}})))},xG=(0,b.withStyles)(x$)(function(e){var t=e.classes,n=e.editing,r=void 0!==n&&n,i=e.innerRef,a=e.initialValues,o=e.onSubmit,s=e.chainIDs,u=void 0===s?[]:s,c=e.accounts,f=void 0===c?[]:c,h=e.p2pKeys,p=void 0===h?[]:h,b=e.ocrKeys,m=void 0===b?[]:b,g=e.ocr2Keys,v=void 0===g?[]:g,y=e.showSubmit,w=void 0!==y&&y;return l.createElement(hT,{innerRef:i,initialValues:a,validationSchema:xH,onSubmit:o},function(e){var n=e.values,i=f.filter(function(e){return e.chain.id==n.chainID&&!e.isDisabled});return l.createElement(hR,{"data-testid":"feeds-manager-form",id:"chain-configuration-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"chainType",name:"chainType",label:"Chain Type",select:!0,required:!0,fullWidth:!0,disabled:!0},l.createElement(tE.default,{key:"EVM",value:"EVM"},"EVM"))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"chainID",name:"chainID",label:"Chain ID",required:!0,fullWidth:!0,select:!0,disabled:r,inputProps:{"data-testid":"chainID-input"},FormHelperTextProps:{"data-testid":"chainID-helper-text"}},u.map(function(e){return l.createElement(tE.default,{key:e,value:e},e)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(xz,{component:hX,id:"accountAddr",name:"accountAddr",label:"Account Address",inputProps:{"data-testid":"accountAddr-input"},required:!0,fullWidth:!0,select:!0,helperText:"The account address used for this chain",chainAccounts:i,FormHelperTextProps:{"data-testid":"accountAddr-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"adminAddr",name:"adminAddr",label:"Admin Address",required:!0,fullWidth:!0,helperText:"The address used for LINK payments",FormHelperTextProps:{"data-testid":"adminAddr-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,null,"Supported Job Types")),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"fluxMonitorEnabled",type:"checkbox",Label:{label:"Flux Monitor"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr1Enabled",type:"checkbox",Label:{label:"OCR"}}),n.ocr1Enabled&&l.createElement(ii.default,{className:t.supportedJobOptionsPaper},l.createElement(d.Z,{container:!0,spacing:8},l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr1IsBootstrap",type:"checkbox",Label:{label:"Is this node running as a bootstrap peer?"}})),n.ocr1IsBootstrap?l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"ocr1Multiaddr",name:"ocr1Multiaddr",label:"Multiaddr",required:!0,fullWidth:!0,helperText:"The OCR Multiaddr which oracles use to query for network information",FormHelperTextProps:{"data-testid":"ocr1Multiaddr-helper-text"}})):l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr1P2PPeerID",name:"ocr1P2PPeerID",label:"Peer ID",select:!0,required:!0,fullWidth:!0,helperText:"The Peer ID used for this chain",FormHelperTextProps:{"data-testid":"ocr1P2PPeerID-helper-text"}},p.map(function(e){return l.createElement(tE.default,{key:e.peerID,value:e.peerID},e.peerID)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr1KeyBundleID",name:"ocr1KeyBundleID",label:"Key Bundle ID",select:!0,required:!0,fullWidth:!0,helperText:"The OCR Key Bundle ID used for this chain",FormHelperTextProps:{"data-testid":"ocr1KeyBundleID-helper-text"}},m.map(function(e){return l.createElement(tE.default,{key:e.id,value:e.id},e.id)})))))))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr2Enabled",type:"checkbox",Label:{label:"OCR2"}}),n.ocr2Enabled&&l.createElement(ii.default,{className:t.supportedJobOptionsPaper},l.createElement(d.Z,{container:!0,spacing:8},l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:h2,name:"ocr2IsBootstrap",type:"checkbox",Label:{label:"Is this node running as a bootstrap peer?"}})),n.ocr2IsBootstrap?l.createElement(d.Z,{item:!0,xs:12},l.createElement(hP,{component:hX,id:"ocr2Multiaddr",name:"ocr2Multiaddr",label:"Multiaddr",required:!0,fullWidth:!0,helperText:"The OCR2 Multiaddr which oracles use to query for network information",FormHelperTextProps:{"data-testid":"ocr2Multiaddr-helper-text"}})):l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr2P2PPeerID",name:"ocr2P2PPeerID",label:"Peer ID",select:!0,required:!0,fullWidth:!0,helperText:"The Peer ID used for this chain",FormHelperTextProps:{"data-testid":"ocr2P2PPeerID-helper-text"}},p.map(function(e){return l.createElement(tE.default,{key:e.peerID,value:e.peerID},e.peerID)}))),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hP,{component:hX,id:"ocr2KeyBundleID",name:"ocr2KeyBundleID",label:"Key Bundle ID",select:!0,required:!0,fullWidth:!0,helperText:"The OCR2 Key Bundle ID used for this chain",FormHelperTextProps:{"data-testid":"ocr2KeyBundleID-helper-text"}},v.map(function(e){return l.createElement(tE.default,{key:e.id,value:e.id},e.id)}))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,null,"Supported Plugins")),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2CommitPluginEnabled",type:"checkbox",Label:{label:"Commit"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2ExecutePluginEnabled",type:"checkbox",Label:{label:"Execute"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2RebalancerPluginEnabled",type:"checkbox",Label:{label:"Rebalancer"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2MedianPluginEnabled",type:"checkbox",Label:{label:"Median"}})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(hP,{component:h2,name:"ocr2MercuryPluginEnabled",type:"checkbox",Label:{label:"Mercury"}})),l.createElement(d.Z,{item:!0,xs:12,md:12},l.createElement(hP,{component:hX,id:"ocr2ForwarderAddress",name:"ocr2ForwarderAddress",label:"Forwarder Address (optional)",fullWidth:!0,helperText:"The forwarder address from the Operator Forwarder Contract",FormHelperTextProps:{"data-testid":"ocr2ForwarderAddress-helper-text"}}))))))),w&&l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ok.default,{variant:"contained",color:"primary",type:"submit",size:"large"},"Submit"))))})}),xW=function(e){var t=e.onClose,n=e.open,r=e.onSubmit,i=l.useRef(),a=i$({fetchPolicy:"network-only"}).data,o=_K({fetchPolicy:"cache-and-network"}).data,s=SV({fetchPolicy:"cache-and-network"}).data,u=EO({fetchPolicy:"cache-and-network"}).data,c=E2({fetchPolicy:"cache-and-network"}).data,f={chainID:"",chainType:"EVM",accountAddr:"",adminAddr:"",accountAddrPubKey:"",fluxMonitorEnabled:!1,ocr1Enabled:!1,ocr1IsBootstrap:!1,ocr1Multiaddr:"",ocr1P2PPeerID:"",ocr1KeyBundleID:"",ocr2Enabled:!1,ocr2IsBootstrap:!1,ocr2Multiaddr:"",ocr2P2PPeerID:"",ocr2KeyBundleID:"",ocr2CommitPluginEnabled:!1,ocr2ExecutePluginEnabled:!1,ocr2MedianPluginEnabled:!1,ocr2MercuryPluginEnabled:!1,ocr2RebalancerPluginEnabled:!1,ocr2ForwarderAddress:""},d=a?a.chains.results.map(function(e){return e.id}):[],h=o?o.ethKeys.results:[],p=s?s.p2pKeys.results:[],b=u?u.ocrKeyBundles.results:[],m=c?c.ocr2KeyBundles.results:[];return l.createElement(aD.Z,{onClose:t,open:n,disableBackdropClick:!0},l.createElement(oO.Z,{disableTypography:!0},l.createElement(x.default,{variant:"body2"},"New Supported Chain")),l.createElement(oT.Z,null,l.createElement(xG,{innerRef:i,initialValues:f,onSubmit:r,chainIDs:d,accounts:h,p2pKeys:p,ocrKeys:b,ocr2Keys:m})),l.createElement(ox.Z,null,l.createElement(ok.default,{onClick:t},"Cancel"),l.createElement(ok.default,{color:"primary",type:"submit",form:"chain-configuration-form",variant:"contained"},"Submit")))},xK=function(e){var t=e.cfg,n=e.onClose,r=e.open,i=e.onSubmit,a=l.useRef(),o=i$({fetchPolicy:"network-only"}).data,s=_K({fetchPolicy:"cache-and-network"}).data,u=SV({fetchPolicy:"cache-and-network"}).data,c=EO({fetchPolicy:"cache-and-network"}).data,f=E2({fetchPolicy:"cache-and-network"}).data;if(!t)return null;var d={chainID:t.chainID,chainType:"EVM",accountAddr:t.accountAddr,adminAddr:t.adminAddr,accountAddrPubKey:t.accountAddrPubKey,fluxMonitorEnabled:t.fluxMonitorJobConfig.enabled,ocr1Enabled:t.ocr1JobConfig.enabled,ocr1IsBootstrap:t.ocr1JobConfig.isBootstrap,ocr1Multiaddr:t.ocr1JobConfig.multiaddr,ocr1P2PPeerID:t.ocr1JobConfig.p2pPeerID,ocr1KeyBundleID:t.ocr1JobConfig.keyBundleID,ocr2Enabled:t.ocr2JobConfig.enabled,ocr2IsBootstrap:t.ocr2JobConfig.isBootstrap,ocr2Multiaddr:t.ocr2JobConfig.multiaddr,ocr2P2PPeerID:t.ocr2JobConfig.p2pPeerID,ocr2KeyBundleID:t.ocr2JobConfig.keyBundleID,ocr2CommitPluginEnabled:t.ocr2JobConfig.plugins.commit,ocr2ExecutePluginEnabled:t.ocr2JobConfig.plugins.execute,ocr2MedianPluginEnabled:t.ocr2JobConfig.plugins.median,ocr2MercuryPluginEnabled:t.ocr2JobConfig.plugins.mercury,ocr2RebalancerPluginEnabled:t.ocr2JobConfig.plugins.rebalancer,ocr2ForwarderAddress:t.ocr2JobConfig.forwarderAddress},h=o?o.chains.results.map(function(e){return e.id}):[],p=s?s.ethKeys.results:[],b=u?u.p2pKeys.results:[],m=c?c.ocrKeyBundles.results:[],g=f?f.ocr2KeyBundles.results:[];return l.createElement(aD.Z,{onClose:n,open:r,disableBackdropClick:!0},l.createElement(oO.Z,{disableTypography:!0},l.createElement(x.default,{variant:"body2"},"Edit Supported Chain")),l.createElement(oT.Z,null,l.createElement(xG,{innerRef:a,initialValues:d,onSubmit:i,chainIDs:h,accounts:p,p2pKeys:b,ocrKeys:m,ocr2Keys:g,editing:!0})),l.createElement(ox.Z,null,l.createElement(ok.default,{onClick:n},"Cancel"),l.createElement(ok.default,{color:"primary",type:"submit",form:"chain-configuration-form",variant:"contained"},"Submit")))};function xV(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xq(){var e=xV(["\n fragment FeedsManager_ChainConfigFields on FeedsManagerChainConfig {\n id\n chainID\n chainType\n accountAddr\n adminAddr\n accountAddrPubKey\n fluxMonitorJobConfig {\n enabled\n }\n ocr1JobConfig {\n enabled\n isBootstrap\n multiaddr\n p2pPeerID\n keyBundleID\n }\n ocr2JobConfig {\n enabled\n isBootstrap\n multiaddr\n forwarderAddress\n p2pPeerID\n keyBundleID\n plugins {\n commit\n execute\n median\n mercury\n rebalancer\n }\n }\n }\n"]);return xq=function(){return e},e}function xZ(){var e=xV(["\n ","\n fragment FeedsManagerFields on FeedsManager {\n id\n name\n uri\n publicKey\n isConnectionActive\n chainConfigs {\n ...FeedsManager_ChainConfigFields\n }\n }\n"]);return xZ=function(){return e},e}function xX(){var e=xV(["\n fragment FeedsManager_JobProposalsFields on JobProposal {\n id\n name\n externalJobID\n remoteUUID\n status\n pendingUpdate\n latestSpec {\n createdAt\n version\n }\n }\n"]);return xX=function(){return e},e}function xJ(){var e=xV(["\n ","\n ","\n fragment FeedsManagerPayload_ResultsFields on FeedsManager {\n ...FeedsManagerFields\n jobProposals {\n ...FeedsManager_JobProposalsFields\n }\n }\n"]);return xJ=function(){return e},e}function xQ(){var e=xV(["\n ","\n query FetchFeedManagersWithProposals {\n feedsManagers {\n results {\n ...FeedsManagerPayload_ResultsFields\n }\n }\n }\n"]);return xQ=function(){return e},e}var x1=n0(xq()),x0=n0(xZ(),x1),x2=n0(xX()),x3=n0(xJ(),x0,x2),x4=n0(xQ(),x3),x6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return rv(x4,e)};function x5(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TZ,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TJ={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TQ=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r5.Z,null,l.createElement(sl.Z,{title:"Register Feeds Manager"}),l.createElement(aW.Z,null,l.createElement(xl,{initialValues:TJ,onSubmit:t})))))};function T1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return ME(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ok.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ok.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mP.Z,{defaultExpanded:0===n,key:n},l.createElement(mR.Z,{expandIcon:l.createElement(gh.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Es.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aO,{tooltip:!0},e.createdAt)))),l.createElement(mj.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ok.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gd,{language:"toml",style:gs,"data-testid":"codeblock"},e.definition)))}),l.createElement(oC,{open:null!=c,title:c?MM[c.action].title:"",body:c?MM[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Md,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MA(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ML(){var e=MA(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ML=function(){return e},e}var MC=n0(ML(),Mx),MI=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(ig,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iy,null,"Job Proposal #",a.id))),l.createElement(Mo,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(Tq,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(MO,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(37703),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(37703),a=n(5977),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(39814),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(37703),a=n(97779),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ru,ZT:()=>i,_T:()=>o,ev:()=>c,mG:()=>s,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&Object.prototype.propertyIsEnumerable.call(e,r[i])&&(n[r[i]]=e[r[i]]);return n}function s(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||(n=Promise))(function(n,a){function o(e){try{u(r.next(e))}catch(t){a(t)}}function s(e){try{u(r.throw(e))}catch(t){a(t)}}function u(e){e.done?n(e.value):i(e.value).then(o,s)}u((r=r.apply(e,t||[])).next())})}function u(e,t){var n,r,i,a,o={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return a={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(e){return function(t){return u([e,t])}}function u(a){if(n)throw TypeError("Generator is already executing.");for(;o;)try{if(n=1,r&&(i=2&a[0]?r.return:a[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,a[1])).done)return i;switch(r=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return o.label++,{value:a[1],done:!1};case 5:o.label++,r=a[1],a=[0];continue;case 7:a=o.ops.pop(),o.trys.pop();continue;default:if(!(i=(i=o.trys).length>0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]r})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}e.exports=i,e.exports.__esModule=!0,e.exports.default=e.exports},7071(e){function t(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},94993(e,t,n){var r=n(18698).default,i=n(66115);function a(e,t){if(t&&("object"===r(t)||"function"==typeof t))return t;if(void 0!==t)throw TypeError("Derived constructors may only return object or undefined");return i(e)}e.exports=a,e.exports.__esModule=!0,e.exports.default=e.exports},6015(e){function t(n,r){return e.exports=t=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},e.exports.__esModule=!0,e.exports.default=e.exports,t(n,r)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},861(e,t,n){var r=n(63405),i=n(79498),a=n(86116),o=n(42281);function s(e){return r(e)||i(e)||a(e)||o()}e.exports=s,e.exports.__esModule=!0,e.exports.default=e.exports},18698(e){function t(n){return e.exports=t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.__esModule=!0,e.exports.default=e.exports,t(n)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},86116(e,t,n){var r=n(73897);function i(e,t){if(e){if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}}e.exports=i,e.exports.__esModule=!0,e.exports.default=e.exports},1644(e,t,n){"use strict";var r,i;function a(e){return!!e&&e<7}n.d(t,{I:()=>r,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(70655);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(70655),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},4942(e,t,n){"use strict";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}n.d(t,{Z:()=>r})},87462(e,t,n){"use strict";function r(){return(r=Object.assign?Object.assign.bind():function(e){for(var t=1;tr})},51721(e,t,n){"use strict";function r(e,t){return(r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e})(e,t)}function i(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>i})},63366(e,t,n){"use strict";function r(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}n.d(t,{Z:()=>r})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(37703),p=__webpack_require__(97779),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t6(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t8("(",t6(e.variableDefinitions,", "),")"),i=t6(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t6([t,t6([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t8(" = ",r)+t8(" ",t6(i," "))},SelectionSet:function(e){return t5(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t8("",t,": ")+n,s=o+t8("(",t6(r,", "),")");return s.length>t2&&(s=o+t8("(\n",t9(t6(r,"\n")),"\n)")),t6([s,t6(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t8(" ",t6(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t6(["...",t8("on ",t),t6(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t8("(",t6(r,", "),")")," ")+"on ".concat(n," ").concat(t8("",t6(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t6(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t6(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t8("(",t6(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t6(["schema",t6(t," "),t5(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t6(["scalar",e.name,t6(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["type",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t8("(\n",t9(t6(n,"\n")),"\n)"):t8("(",t6(n,", "),")"))+": "+r+t8(" ",t6(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t6([t+": "+n,t8("= ",r),t6(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["interface",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t6(["union",t,t6(n," "),r&&0!==r.length?"= "+t6(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t6(["enum",t,t6(n," "),t5(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t6([e.name,t6(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t6(["input",t,t6(n," "),t5(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t8("(\n",t9(t6(n,"\n")),"\n)"):t8("(",t6(n,", "),")"))+(r?" repeatable":"")+" on "+t6(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t6(["extend schema",t6(t," "),t5(n)]," ")},ScalarTypeExtension:function(e){var t;return t6(["extend scalar",e.name,t6(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["extend type",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t6(["extend interface",t,t8("implements ",t6(n," & ")),t6(r," "),t5(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t6(["extend union",t,t6(n," "),r&&0!==r.length?"= "+t6(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t6(["extend enum",t,t6(n," "),t5(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t6(["extend input",t,t6(n," "),t5(r)]," ")}};function t4(e){return function(t){return t6([t.description,e(t)],"\n")}}function t6(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t5(e){return t8("{\n",t9(t6(e,"\n")),"\n}")}function t8(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t9(e){return t8(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n6(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n5(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n8(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n9(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e8(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n9(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n9(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r6=new(t_.mr?WeakMap:Map);function r5(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r6.set(e,(r6.get(e)+1)%1e15),n.apply(this,arguments)})}function r8(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r9=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r6.has(n)||(r6.set(n,0),r5(n,"evict"),r5(n,"modify"),r5(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r8(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r8(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r6.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r6.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e9(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r9(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r9&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n5(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r9(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e9(e6(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e8(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e9(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i5(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i8(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i9(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i5(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i6=[];function i5(e,t){var n=e.map;return n.has(t)||n.set(t,i6.pop()||{map:new Map}),n.get(t)}function i8(e,t){if(e===t||!t||i9(t))return e;if(!e||i9(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i8(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i8(t.map.get(n),e.map.get(n)))})}return a}function i9(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i9(r)&&(i6.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","StandardCapabilitiesSpec","VRFSpec","WebhookSpec","WorkflowSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.026013f04da39527a75d.js.gz b/core/web/assets/main.6f07a88cfc748f57e21d.js.gz similarity index 94% rename from core/web/assets/main.026013f04da39527a75d.js.gz rename to core/web/assets/main.6f07a88cfc748f57e21d.js.gz index 8524ee8d01a..1a833982299 100644 Binary files a/core/web/assets/main.026013f04da39527a75d.js.gz and b/core/web/assets/main.6f07a88cfc748f57e21d.js.gz differ diff --git a/core/web/auth/auth_test.go b/core/web/auth/auth_test.go index 9896a2e359a..25479409545 100644 --- a/core/web/auth/auth_test.go +++ b/core/web/auth/auth_test.go @@ -274,19 +274,24 @@ var routesRolesMap = [...]routeRules{ {"POST", "/v2/keys/p2p/export/MOCK", false, false, false}, {"GET", "/v2/keys/solana", true, true, true}, {"GET", "/v2/keys/cosmos", true, true, true}, - {"GET", "/v2/keys/dkgsign", true, true, true}, + {"GET", "/v2/keys/starknet", true, true, true}, + {"GET", "/v2/keys/aptos", true, true, true}, {"POST", "/v2/keys/solana", false, false, true}, {"POST", "/v2/keys/cosmos", false, false, true}, - {"POST", "/v2/keys/dkgsign", false, false, true}, + {"POST", "/v2/keys/starknet", false, false, true}, + {"POST", "/v2/keys/aptos", false, false, true}, {"DELETE", "/v2/keys/solana/MOCK", false, false, false}, {"DELETE", "/v2/keys/cosmos/MOCK", false, false, false}, - {"DELETE", "/v2/keys/dkgsign/MOCK", false, false, false}, + {"DELETE", "/v2/keys/starknet/MOCK", false, false, false}, + {"DELETE", "/v2/keys/aptos/MOCK", false, false, false}, {"POST", "/v2/keys/solana/import", false, false, false}, {"POST", "/v2/keys/cosmos/import", false, false, false}, - {"POST", "/v2/keys/dkgsign/import", false, false, false}, + {"POST", "/v2/keys/starknet/import", false, false, false}, + {"POST", "/v2/keys/aptos/import", false, false, false}, {"POST", "/v2/keys/solana/export/MOCK", false, false, false}, {"POST", "/v2/keys/cosmos/export/MOCK", false, false, false}, - {"POST", "/v2/keys/dkgsign/export/MOCK", false, false, false}, + {"POST", "/v2/keys/starknet/export/MOCK", false, false, false}, + {"POST", "/v2/keys/aptos/export/MOCK", false, false, false}, {"GET", "/v2/keys/vrf", true, true, true}, {"POST", "/v2/keys/vrf", false, false, true}, {"DELETE", "/v2/keys/vrf/MOCK", false, false, false}, diff --git a/core/web/dkgencrypt_keys_controller.go b/core/web/dkgencrypt_keys_controller.go deleted file mode 100644 index 5bd6fe2f347..00000000000 --- a/core/web/dkgencrypt_keys_controller.go +++ /dev/null @@ -1,17 +0,0 @@ -package web - -import ( - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func NewDKGEncryptKeysController(app chainlink.Application) KeysController { - return NewKeysController[dkgencryptkey.Key, presenters.DKGEncryptKeyResource]( - app.GetKeyStore().DKGEncrypt(), - app.GetLogger(), - app.GetAuditLogger(), - "dkgencryptKey", - presenters.NewDKGEncryptKeyResource, - presenters.NewDKGEncryptKeyResources) -} diff --git a/core/web/dkgencrypt_keys_controller_test.go b/core/web/dkgencrypt_keys_controller_test.go deleted file mode 100644 index 0f4344fdc23..00000000000 --- a/core/web/dkgencrypt_keys_controller_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package web_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/web" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func TestDKGEncryptKeysController_Index_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGEncryptKeysControllerTests(t) - keys, _ := keyStore.DKGEncrypt().GetAll() - - response, cleanup := client.Get("/v2/keys/dkgencrypt") - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - - resources := []presenters.DKGEncryptKeyResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resources) - assert.NoError(t, err) - - assert.Len(t, resources, len(keys)) - - assert.Equal(t, keys[0].ID(), resources[0].ID) - assert.Equal(t, keys[0].PublicKeyString(), resources[0].PublicKey) -} - -func TestDKGEncryptKeysController_Create_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGEncryptKeysControllerTests(t) - - response, cleanup := client.Post("/v2/keys/dkgencrypt", nil) - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - - keys, _ := keyStore.DKGEncrypt().GetAll() - assert.Len(t, keys, 2) - - resource := presenters.DKGEncryptKeyResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resource) - assert.NoError(t, err) - - // the order in which keys are returned by GetAll is non-deterministic - // due to map iteration non-determinism. - found := false - for _, key := range keys { - if key.ID() == resource.ID { - assert.Equal(t, key.PublicKeyString(), resource.PublicKey) - found = true - } - } - assert.True(t, found) - - _, err = keyStore.DKGEncrypt().Get(resource.ID) - assert.NoError(t, err) -} - -func TestDKGEncryptKeysController_Delete_NonExistentDKGEncryptKeyID(t *testing.T) { - t.Parallel() - - client, _ := setupDKGEncryptKeysControllerTests(t) - - response, cleanup := client.Delete("/v2/keys/dkgencrypt/" + "nonexistentKey") - t.Cleanup(cleanup) - assert.Equal(t, http.StatusNotFound, response.StatusCode) -} - -func TestDKGEncryptKeysController_Delete_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGEncryptKeysControllerTests(t) - - keys, _ := keyStore.DKGEncrypt().GetAll() - initialLength := len(keys) - - response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/dkgencrypt/%s", keys[0].ID())) - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - assert.Error(t, utils.JustError(keyStore.DKGEncrypt().Get(keys[0].ID()))) - - afterKeys, err := keyStore.DKGEncrypt().GetAll() - assert.NoError(t, err) - assert.Equal(t, initialLength-1, len(afterKeys)) -} - -func setupDKGEncryptKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { - t.Helper() - - app := cltest.NewApplication(t) - ctx := testutils.Context(t) - require.NoError(t, app.Start(ctx)) - require.NoError(t, app.KeyStore.DKGEncrypt().Add(ctx, cltest.DefaultDKGEncryptKey)) - - client := app.NewHTTPClient(nil) - - return client, app.GetKeyStore() -} diff --git a/core/web/dkgsign_keys_controller.go b/core/web/dkgsign_keys_controller.go deleted file mode 100644 index 39cebb03030..00000000000 --- a/core/web/dkgsign_keys_controller.go +++ /dev/null @@ -1,17 +0,0 @@ -package web - -import ( - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func NewDKGSignKeysController(app chainlink.Application) KeysController { - return NewKeysController[dkgsignkey.Key, presenters.DKGSignKeyResource]( - app.GetKeyStore().DKGSign(), - app.GetLogger(), - app.GetAuditLogger(), - "dkgsignKey", - presenters.NewDKGSignKeyResource, - presenters.NewDKGSignKeyResources) -} diff --git a/core/web/dkgsign_keys_controller_test.go b/core/web/dkgsign_keys_controller_test.go deleted file mode 100644 index 01b8489c0b8..00000000000 --- a/core/web/dkgsign_keys_controller_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package web_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/web" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" -) - -func TestDKGSignKeysController_Index_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGSignKeysControllerTests(t) - keys, _ := keyStore.DKGSign().GetAll() - - response, cleanup := client.Get("/v2/keys/dkgsign") - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - - resources := []presenters.DKGSignKeyResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resources) - assert.NoError(t, err) - - assert.Len(t, resources, len(keys)) - - assert.Equal(t, keys[0].ID(), resources[0].ID) - assert.Equal(t, keys[0].PublicKeyString(), resources[0].PublicKey) -} - -func TestDKGSignKeysController_Create_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGSignKeysControllerTests(t) - - response, cleanup := client.Post("/v2/keys/dkgsign", nil) - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - - keys, _ := keyStore.DKGSign().GetAll() - assert.Len(t, keys, 2) - - resource := presenters.DKGSignKeyResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &resource) - assert.NoError(t, err) - - // the order in which keys are returned by GetAll is non-deterministic - // due to map iteration non-determinism. - found := false - for _, key := range keys { - if key.ID() == resource.ID { - assert.Equal(t, key.PublicKeyString(), resource.PublicKey) - found = true - } - } - assert.True(t, found) - - _, err = keyStore.DKGSign().Get(resource.ID) - assert.NoError(t, err) -} - -func TestDKGSignKeysController_Delete_NonExistentDKGSignKeyID(t *testing.T) { - t.Parallel() - - client, _ := setupDKGSignKeysControllerTests(t) - - response, cleanup := client.Delete("/v2/keys/dkgsign/" + "nonexistentKey") - t.Cleanup(cleanup) - assert.Equal(t, http.StatusNotFound, response.StatusCode) -} - -func TestDKGSignKeysController_Delete_HappyPath(t *testing.T) { - t.Parallel() - - client, keyStore := setupDKGSignKeysControllerTests(t) - - keys, _ := keyStore.DKGSign().GetAll() - initialLength := len(keys) - - response, cleanup := client.Delete(fmt.Sprintf("/v2/keys/dkgsign/%s", keys[0].ID())) - t.Cleanup(cleanup) - cltest.AssertServerResponse(t, response, http.StatusOK) - assert.Error(t, utils.JustError(keyStore.DKGSign().Get(keys[0].ID()))) - - afterKeys, err := keyStore.DKGSign().GetAll() - assert.NoError(t, err) - assert.Equal(t, initialLength-1, len(afterKeys)) -} - -func setupDKGSignKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keystore.Master) { - t.Helper() - - app := cltest.NewApplication(t) - ctx := testutils.Context(t) - require.NoError(t, app.Start(ctx)) - require.NoError(t, app.KeyStore.DKGSign().Add(ctx, cltest.DefaultDKGSignKey)) - - client := app.NewHTTPClient(nil) - - return client, app.GetKeyStore() -} diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 0401dbdb8c8..60abe61537f 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -28,6 +28,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -270,6 +271,25 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.Equal(t, "CRON_TZ=UTC * 0 0 1 1 *", jb.CronSpec.CronSchedule) }, }, + { + name: "cron-evm-chain-id", + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(testspecs.CronSpecEVMChainIDTemplate, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { + require.Equal(t, http.StatusOK, r.StatusCode) + resource := presenters.JobResource{} + err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) + assert.NoError(t, err) + + jb, err := jorm.FindJob(testutils.Context(t), mustInt32FromString(t, resource.ID)) + require.NoError(t, err) + require.NotNil(t, jb.CronSpec) + + assert.NotNil(t, resource.PipelineSpec.DotDAGSource) + require.Equal(t, ubig.NewI(42), jb.CronSpec.EVMChainID) + }, + }, { name: "directrequest", tomlTemplate: func(nameAndExternalJobID string) string { @@ -464,6 +484,7 @@ targets: t.Run(c.name, func(t *testing.T) { nameAndExternalJobID := uuid.New().String() toml := c.tomlTemplate(nameAndExternalJobID) + t.Log("Job toml:", toml) body, err := json.Marshal(web.CreateJobRequest{ TOML: toml, }) diff --git a/core/web/presenters/aptos_key.go b/core/web/presenters/aptos_key.go new file mode 100644 index 00000000000..6460c325f97 --- /dev/null +++ b/core/web/presenters/aptos_key.go @@ -0,0 +1,32 @@ +package presenters + +import "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/aptoskey" + +// AptosKeyResource represents a Aptos key JSONAPI resource. +type AptosKeyResource struct { + JAID + PubKey string `json:"publicKey"` +} + +// GetName implements the api2go EntityNamer interface +func (AptosKeyResource) GetName() string { + return "encryptedAptosKeys" +} + +func NewAptosKeyResource(key aptoskey.Key) *AptosKeyResource { + r := &AptosKeyResource{ + JAID: JAID{ID: key.ID()}, + PubKey: key.PublicKeyStr(), + } + + return r +} + +func NewAptosKeyResources(keys []aptoskey.Key) []AptosKeyResource { + rs := []AptosKeyResource{} + for _, key := range keys { + rs = append(rs, *NewAptosKeyResource(key)) + } + + return rs +} diff --git a/core/web/presenters/dkgencrypt_key.go b/core/web/presenters/dkgencrypt_key.go deleted file mode 100644 index ae715b79048..00000000000 --- a/core/web/presenters/dkgencrypt_key.go +++ /dev/null @@ -1,38 +0,0 @@ -package presenters - -import ( - "github.com/manyminds/api2go/jsonapi" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" -) - -// DKGEncryptKeyResource is just that. -type DKGEncryptKeyResource struct { - JAID - PublicKey string `json:"publicKey"` -} - -var _ jsonapi.EntityNamer = DKGEncryptKeyResource{} - -// GetName implements jsonapi.EntityNamer -func (DKGEncryptKeyResource) GetName() string { - return "encryptedDKGEncryptKeys" -} - -// NewDKGEncryptKeyResource creates a new DKGEncryptKeyResource from the given DKG sign key. -func NewDKGEncryptKeyResource(key dkgencryptkey.Key) *DKGEncryptKeyResource { - return &DKGEncryptKeyResource{ - JAID: JAID{ - ID: key.ID(), - }, - PublicKey: key.PublicKeyString(), - } -} - -// NewDKGEncryptKeyResources creates many DKGEncryptKeyResource objects from the given DKG sign keys. -func NewDKGEncryptKeyResources(keys []dkgencryptkey.Key) (resources []DKGEncryptKeyResource) { - for _, key := range keys { - resources = append(resources, *NewDKGEncryptKeyResource(key)) - } - return -} diff --git a/core/web/presenters/dkgsign_key.go b/core/web/presenters/dkgsign_key.go deleted file mode 100644 index e6aa95ff314..00000000000 --- a/core/web/presenters/dkgsign_key.go +++ /dev/null @@ -1,38 +0,0 @@ -package presenters - -import ( - "github.com/manyminds/api2go/jsonapi" - - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" -) - -// DKGSignKeyResource is just that. -type DKGSignKeyResource struct { - JAID - PublicKey string `json:"publicKey"` -} - -var _ jsonapi.EntityNamer = DKGSignKeyResource{} - -// GetName implements jsonapi.EntityNamer -func (DKGSignKeyResource) GetName() string { - return "encryptedDKGSignKeys" -} - -// NewDKGSignKeyResource creates a new DKGSignKeyResource from the given DKG sign key. -func NewDKGSignKeyResource(key dkgsignkey.Key) *DKGSignKeyResource { - return &DKGSignKeyResource{ - JAID: JAID{ - ID: key.ID(), - }, - PublicKey: key.PublicKeyString(), - } -} - -// NewDKGSignKeyResources creates many DKGSignKeyResource objects from the given DKG sign keys. -func NewDKGSignKeyResources(keys []dkgsignkey.Key) (resources []DKGSignKeyResource) { - for _, key := range keys { - resources = append(resources, *NewDKGSignKeyResource(key)) - } - return -} diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 8d7dab626cb..ad6bf617a82 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -252,9 +252,10 @@ func NewWebhookSpec(spec *job.WebhookSpec) *WebhookSpec { // CronSpec defines the spec details of a Cron Job type CronSpec struct { - CronSchedule string `json:"schedule" tom:"schedule"` + CronSchedule string `json:"schedule"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *big.Big `json:"evmChainID"` } // NewCronSpec generates a new CronSpec from a job.CronSpec @@ -263,6 +264,7 @@ func NewCronSpec(spec *job.CronSpec) *CronSpec { CronSchedule: spec.CronSchedule, CreatedAt: spec.CreatedAt, UpdatedAt: spec.UpdatedAt, + EVMChainID: spec.EVMChainID, } } diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 80856daa8ef..5de71f918e3 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -374,6 +374,7 @@ func TestJob(t *testing.T) { CronSchedule: cronSchedule, CreatedAt: timestamp, UpdatedAt: timestamp, + EVMChainID: evmChainID, }, ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), PipelineSpec: &pipeline.Spec{ @@ -404,7 +405,8 @@ func TestJob(t *testing.T) { "cronSpec": { "schedule": "%s", "createdAt":"2000-01-01T00:00:00Z", - "updatedAt":"2000-01-01T00:00:00Z" + "updatedAt":"2000-01-01T00:00:00Z", + "evmChainID":"42" }, "fluxMonitorSpec": null, "gasLimit": null, diff --git a/core/web/resolver/ocr2_keys.go b/core/web/resolver/ocr2_keys.go index df184109331..d04ebbd0e2f 100644 --- a/core/web/resolver/ocr2_keys.go +++ b/core/web/resolver/ocr2_keys.go @@ -25,6 +25,8 @@ const ( OCR2ChainTypeSolana = "SOLANA" // OCR2ChainTypeStarkNet defines OCR2 StarkNet Chain Type OCR2ChainTypeStarkNet = "STARKNET" + // OCRChainTypeAptos defines OCR Aptos Chain Type + OCRChainTypeAptos = "APTOS" ) // ToOCR2ChainType turns a valid string into a OCR2ChainType @@ -38,6 +40,8 @@ func ToOCR2ChainType(s string) (OCR2ChainType, error) { return OCR2ChainTypeSolana, nil case string(chaintype.StarkNet): return OCR2ChainTypeStarkNet, nil + case string(chaintype.Aptos): + return OCRChainTypeAptos, nil default: return "", errors.New("unknown ocr2 chain type") } @@ -54,6 +58,8 @@ func FromOCR2ChainType(ct OCR2ChainType) string { return string(chaintype.Solana) case OCR2ChainTypeStarkNet: return string(chaintype.StarkNet) + case OCRChainTypeAptos: + return string(chaintype.Aptos) default: return strings.ToLower(string(ct)) } diff --git a/core/web/resolver/ocr2_keys_test.go b/core/web/resolver/ocr2_keys_test.go index 2269149bc37..033d22799b1 100644 --- a/core/web/resolver/ocr2_keys_test.go +++ b/core/web/resolver/ocr2_keys_test.go @@ -41,6 +41,7 @@ func TestResolver_GetOCR2KeyBundles(t *testing.T) { ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(1), "cosmos"), ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(1), "solana"), ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(1), "starknet"), + ocr2key.MustNewInsecure(keystest.NewRandReaderFromSeed(1), "aptos"), } expectedBundles := []map[string]interface{}{} for _, k := range fakeKeys { diff --git a/core/web/resolver/spec.go b/core/web/resolver/spec.go index b3c22b3b342..00b2442acab 100644 --- a/core/web/resolver/spec.go +++ b/core/web/resolver/spec.go @@ -141,6 +141,17 @@ func (r *CronSpecResolver) Schedule() string { return r.spec.CronSchedule } +// EVMChainID resolves the spec's evm chain id. +func (r *CronSpecResolver) EVMChainID() *string { + if r.spec.EVMChainID == nil { + return nil + } + + chainID := r.spec.EVMChainID.String() + + return &chainID +} + // CreatedAt resolves the spec's created at timestamp. func (r *CronSpecResolver) CreatedAt() graphql.Time { return graphql.Time{Time: r.spec.CreatedAt} diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 2d5dcc71d1f..69d6a56509c 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -42,6 +42,7 @@ func TestResolver_CronSpec(t *testing.T) { Type: job.Cron, CronSpec: &job.CronSpec{ CronSchedule: "CRON_TZ=UTC 0 0 1 1 *", + EVMChainID: ubig.NewI(42), CreatedAt: f.Timestamp(), }, }, nil) @@ -54,6 +55,7 @@ func TestResolver_CronSpec(t *testing.T) { __typename ... on CronSpec { schedule + evmChainID createdAt } } @@ -67,6 +69,7 @@ func TestResolver_CronSpec(t *testing.T) { "spec": { "__typename": "CronSpec", "schedule": "CRON_TZ=UTC 0 0 1 1 *", + "evmChainID": "42", "createdAt": "2021-01-01T00:00:00Z" } } diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index d69f0aa5064..76326f9a4d4 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -287,6 +287,7 @@ NoNewHeadsThreshold = '1m0s' OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418' RPCDefaultBatchSize = 17 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = true @@ -356,6 +357,8 @@ SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.NodePool.Errors] NonceTooLow = '(: |^)nonce too low' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 13aac2db7fa..8e6682dee3f 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -274,6 +274,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -328,6 +329,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 @@ -370,6 +373,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -424,6 +428,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 @@ -460,6 +466,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -514,6 +521,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 diff --git a/core/web/resolver/testdata/config-multi-chain.toml b/core/web/resolver/testdata/config-multi-chain.toml index 3598e92cdc2..9abb1719402 100644 --- a/core/web/resolver/testdata/config-multi-chain.toml +++ b/core/web/resolver/testdata/config-multi-chain.toml @@ -39,6 +39,7 @@ CPUProfileRate = 7 ChainID = '1' FinalityDepth = 26 FinalityTagEnabled = false +FinalizedBlockOffset = 0 [EVM.OCR2] [EVM.OCR2.Automation] diff --git a/core/web/router.go b/core/web/router.go index 5e90cea237b..6e96b47981b 100644 --- a/core/web/router.go +++ b/core/web/router.go @@ -350,8 +350,7 @@ func v2Routes(app chainlink.Application, r *gin.RouterGroup) { {"solana", NewSolanaKeysController(app)}, {"cosmos", NewCosmosKeysController(app)}, {"starknet", NewStarkNetKeysController(app)}, - {"dkgsign", NewDKGSignKeysController(app)}, - {"dkgencrypt", NewDKGEncryptKeysController(app)}, + {"aptos", NewAptosKeysController(app)}, } { authv2.GET("/keys/"+keys.path, keys.kc.Index) authv2.POST("/keys/"+keys.path, auth.RequiresEditRole(keys.kc.Create)) diff --git a/core/web/schema/type/ocr2_keys.graphql b/core/web/schema/type/ocr2_keys.graphql index 95da9acf71f..c25148c686a 100644 --- a/core/web/schema/type/ocr2_keys.graphql +++ b/core/web/schema/type/ocr2_keys.graphql @@ -3,6 +3,7 @@ enum OCR2ChainType { COSMOS SOLANA STARKNET + APTOS } type OCR2KeyBundle { diff --git a/core/web/schema/type/spec.graphql b/core/web/schema/type/spec.graphql index db33dd14ee2..5a803e2f8ee 100644 --- a/core/web/schema/type/spec.graphql +++ b/core/web/schema/type/spec.graphql @@ -16,6 +16,7 @@ union JobSpec = type CronSpec { schedule: String! + evmChainID: String createdAt: Time! } diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 5f40d9fa69d..9e10615a010 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -1776,6 +1776,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -1830,6 +1831,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -1866,6 +1869,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -1920,6 +1924,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -1956,6 +1962,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2010,6 +2017,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2046,6 +2055,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2100,6 +2110,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2137,6 +2149,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2191,6 +2204,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -2227,6 +2242,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2281,6 +2297,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2317,6 +2335,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2371,6 +2390,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2408,6 +2429,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2462,6 +2484,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2498,6 +2522,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2552,6 +2577,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2587,6 +2614,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2641,6 +2669,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2676,6 +2706,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2730,6 +2761,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2766,6 +2799,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2820,6 +2854,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2857,6 +2893,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -2911,6 +2948,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -2947,6 +2986,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3001,6 +3041,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3037,6 +3079,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3091,6 +3134,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3127,6 +3172,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '12m0s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 15 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3181,6 +3227,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -3217,6 +3265,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '6m0s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 15 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3271,6 +3320,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -3307,6 +3358,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3361,6 +3413,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3397,6 +3451,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3451,6 +3506,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -3487,6 +3544,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '1m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3541,6 +3599,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3577,6 +3637,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '1m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3631,6 +3692,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3667,6 +3730,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '1m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3721,6 +3785,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -3758,6 +3824,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3812,6 +3879,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -3848,6 +3917,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3902,6 +3972,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -3937,6 +4009,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -3991,6 +4064,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4027,6 +4102,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4081,6 +4157,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4117,6 +4195,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '6m0s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 15 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4171,6 +4250,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4207,6 +4288,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4261,6 +4343,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4297,6 +4381,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4351,6 +4436,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4386,6 +4473,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4440,6 +4528,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4476,6 +4566,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '12m0s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4530,6 +4621,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4566,6 +4659,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4620,6 +4714,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4656,6 +4752,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '12m0s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4710,6 +4807,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4746,6 +4845,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4800,6 +4900,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -4835,6 +4937,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4889,6 +4992,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -4925,6 +5030,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -4979,6 +5085,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5015,6 +5123,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5069,6 +5178,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -5106,6 +5217,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5160,6 +5272,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5196,6 +5310,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '1m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5250,6 +5365,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5286,6 +5403,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5340,6 +5458,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5376,6 +5496,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 2 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5430,6 +5551,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5466,6 +5589,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '1m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5520,6 +5644,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5555,6 +5681,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5609,6 +5736,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -5644,6 +5773,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5698,6 +5828,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -5733,6 +5865,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5787,6 +5920,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -5823,6 +5958,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5877,6 +6013,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -5913,6 +6051,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -5967,6 +6106,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -6002,6 +6143,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 100 RPCBlockQueryDelay = 10 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6056,6 +6198,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -6092,6 +6236,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6146,6 +6291,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6182,6 +6329,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6236,6 +6384,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6273,6 +6423,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6327,6 +6478,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6364,6 +6517,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6418,6 +6572,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6454,6 +6610,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6508,6 +6665,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6532,9 +6691,9 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'scroll' FinalityDepth = 10 -FinalityTagEnabled = false +FinalityTagEnabled = true LogBackfillBatchSize = 1000 -LogPollInterval = '3s' +LogPollInterval = '5s' LogKeepBlocksDepth = 100000 LogPrunePageSize = 0 BackupLogPollerBlockDelay = 100 @@ -6544,6 +6703,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6560,25 +6720,25 @@ Enabled = false Enabled = true [GasEstimator] -Mode = 'SuggestedPrice' +Mode = 'BlockHistory' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '0' +PriceMin = '1 wei' LimitDefault = 500000 LimitMax = 500000 LimitMultiplier = '1' LimitTransfer = 21000 -BumpMin = '5 gwei' +BumpMin = '1 gwei' BumpPercent = 20 BumpThreshold = 3 -EIP1559DynamicFees = false +EIP1559DynamicFees = true FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' TipCapMin = '1 wei' [GasEstimator.BlockHistory] BatchSize = 25 -BlockHistorySize = 0 +BlockHistorySize = 24 CheckInclusionBlocks = 12 CheckInclusionPercentile = 90 TransactionPercentile = 60 @@ -6598,6 +6758,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6622,9 +6784,9 @@ BlockBackfillDepth = 10 BlockBackfillSkip = false ChainType = 'scroll' FinalityDepth = 10 -FinalityTagEnabled = false +FinalityTagEnabled = true LogBackfillBatchSize = 1000 -LogPollInterval = '3s' +LogPollInterval = '5s' LogKeepBlocksDepth = 100000 LogPrunePageSize = 0 BackupLogPollerBlockDelay = 100 @@ -6634,6 +6796,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6650,25 +6813,25 @@ Enabled = false Enabled = true [GasEstimator] -Mode = 'SuggestedPrice' +Mode = 'BlockHistory' PriceDefault = '20 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '0' +PriceMin = '1 wei' LimitDefault = 500000 LimitMax = 500000 LimitMultiplier = '1' LimitTransfer = 21000 -BumpMin = '5 gwei' +BumpMin = '1 gwei' BumpPercent = 20 BumpThreshold = 3 -EIP1559DynamicFees = false +EIP1559DynamicFees = true FeeCapDefault = '100 gwei' TipCapDefault = '1 wei' TipCapMin = '1 wei' [GasEstimator.BlockHistory] BatchSize = 25 -BlockHistorySize = 0 +BlockHistorySize = 24 CheckInclusionBlocks = 12 CheckInclusionPercentile = 90 TransactionPercentile = 60 @@ -6688,6 +6851,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6724,6 +6889,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '3m0s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6778,6 +6944,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -6814,6 +6982,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '40s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6868,6 +7037,8 @@ SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 1 @@ -6904,6 +7075,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -6958,6 +7130,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -6994,6 +7168,7 @@ NonceAutoSync = true NoNewHeadsThreshold = '30s' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [Transactions] ForwardersEnabled = false @@ -7048,6 +7223,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [OCR] ContractConfirmations = 4 @@ -7236,6 +7413,22 @@ block, but it is possible to receive a head BEFORE that block is actually available from the connected node via RPC, due to race conditions in the code of the remote ETH node. In this case you will get false "zero" blocks that are missing transactions. +### FinalizedBlockOffset +```toml +FinalizedBlockOffset = 0 # Default +``` +FinalizedBlockOffset defines the number of blocks by which the latest finalized block will be shifted/delayed. +For example, suppose RPC returns block 100 as the latest finalized. In that case, the CL Node will treat block `100 - FinalizedBlockOffset` as the latest finalized block and `latest - FinalityDepth - FinalizedBlockOffset` in case of `FinalityTagEnabled = false.` +With `EnforceRepeatableRead = true,` RPC is considered healthy only if its most recent finalized block is larger or equal to the highest finalized block observed by the CL Node minus `FinalizedBlockOffset.` +Higher values of `FinalizedBlockOffset` with `EnforceRepeatableRead = true` reduce the number of false `FinalizedBlockOutOfSync` declarations on healthy RPCs that are slightly lagging behind due to network delays. +This may increase the number of healthy RPCs and reduce the probability that the CL Node will not have any healthy alternatives to the active RPC. +CAUTION: Setting this to values higher than 0 may delay transaction creation in products (e.g., CCIP, Automation) that base their decision on finalized on-chain events. +PoS chains with `FinalityTagEnabled=true` and batched (epochs) blocks finalization (e.g., Ethereum Mainnet) must be treated with special care as a minor increase in the `FinalizedBlockOffset` may lead to significant delays. +For example, let's say that `FinalizedBlockOffset = 1` and blocks are finalized in batches of 32. +The latest finalized block on chain is 64, so block 63 is the latest finalized for CL Node. +Block 64 will be treated as finalized by CL Node only when chain's latest finalized block is 65. As chain finalizes blocks in batches of 32, +CL Node has to wait for a whole new batch to be finalized to treat block 64 as finalized. + ## EVM.Transactions ```toml [EVM.Transactions] @@ -7743,6 +7936,8 @@ SyncThreshold = 5 # Default LeaseDuration = '0s' # Default NodeIsSyncingEnabled = false # Default FinalizedBlockPollInterval = '5s' # Default +EnforceRepeatableRead = false # Default +DeathDeclarationDelay = '10s' # Default ``` The node pool manages multiple RPC endpoints. @@ -7816,6 +8011,25 @@ reported based on latest block and finality depth. Set to 0 to disable. +### EnforceRepeatableRead +```toml +EnforceRepeatableRead = false # Default +``` +EnforceRepeatableRead defines if Core should only use RPCs whose most recently finalized block is greater or equal to +`highest finalized block - FinalizedBlockOffset`. In other words, exclude RPCs lagging on latest finalized +block. + +Set false to disable + +### DeathDeclarationDelay +```toml +DeathDeclarationDelay = '10s' # Default +``` +DeathDeclarationDelay defines the minimum duration an RPC must be in unhealthy state before producing an error log message. +Larger values might be helpful to reduce the noisiness of health checks like `EnforceRepeatableRead = true', which might be falsely +trigger declaration of `FinalizedBlockOutOfSync` due to insignificant network delays in broadcasting of the finalized state among RPCs. +RPC will not be picked to handle a request even if this option is set to a nonzero value. + ## EVM.NodePool.Errors :warning: **_ADVANCED_**: _Do not change these settings unless you know what you are doing._ ```toml diff --git a/go.md b/go.md index dda7192c1a1..4ef6c4da9e4 100644 --- a/go.md +++ b/go.md @@ -40,8 +40,6 @@ flowchart LR click chainlink-solana href "https://github.com/smartcontractkit/chainlink-solana" chainlink/v2 --> chainlink-starknet/relayer click chainlink-starknet/relayer href "https://github.com/smartcontractkit/chainlink-starknet" - chainlink/v2 --> chainlink-vrf - click chainlink-vrf href "https://github.com/smartcontractkit/chainlink-vrf" chainlink/v2 --> libocr click libocr href "https://github.com/smartcontractkit/libocr" chainlink/v2 --> tdh2/go/ocr2/decryptionplugin @@ -64,7 +62,6 @@ flowchart LR chainlink-solana --> libocr chainlink-starknet/relayer --> chainlink-common chainlink-starknet/relayer --> libocr - chainlink-vrf --> libocr tdh2/go/ocr2/decryptionplugin --> libocr tdh2/go/ocr2/decryptionplugin --> tdh2/go/tdh2 ``` diff --git a/go.mod b/go.mod index 8745148e4c5..18c825478b5 100644 --- a/go.mod +++ b/go.mod @@ -72,17 +72,16 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d - github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba - github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 - github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wsrpc v0.8.1 + github.com/smartcontractkit/wsrpc v0.7.3 github.com/spf13/cast v1.6.0 github.com/stretchr/testify v1.9.0 github.com/test-go/testify v1.1.4 @@ -288,7 +287,6 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -353,6 +351,10 @@ replace ( // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 + // until nolag updates merged upstream + github.com/mitchellh/mapstructure => github.com/nolag/mapstructure v1.5.2-0.20240625151721-90ea83a3f479 + // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f + ) diff --git a/go.sum b/go.sum index 84c6e23cd01..b9d5ccb1302 100644 --- a/go.sum +++ b/go.sum @@ -622,6 +622,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -965,11 +966,6 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -1002,6 +998,8 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nolag/mapstructure v1.5.2-0.20240625151721-90ea83a3f479 h1:1jCGDLFXDOHF2sdeTJYKrIuSLGMpQZpgXXHNGXR5Ouk= +github.com/nolag/mapstructure v1.5.2-0.20240625151721-90ea83a3f479/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -1172,32 +1170,30 @@ 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.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf h1:d9AS/K8RSVG64USb20N/U7RaPOsYPcmuLGJq7iE+caM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf/go.mod h1:L32xvCpk84Nglit64OhySPMP1tM3TTBK7Tw0qZl7Sd4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d h1:5tgMC5Gi2UAOKZ+m28W8ubjLeR0pQCAcrz6eQ0rW510= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe h1:lYyWmjheglMu0y3JmfSqs9Dm4tZO34RmbUTOtQ4CadE= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe/go.mod h1:EWvSuqIJUYXZLEHewC7WCaPylM2jyjF3Q36BZPS4MoI= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 h1:TMOoYaeSDkkI3jkCH7lKHOZaLkeDuxFTNC+XblD6M0M= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 h1:Vs6myS+bpPwb8chUY7XxveJyhvejknhOmhDTddgsK5I= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527/go.mod h1:KRK7KlAEpmORi+nJgT0vxQVWvlLEBQ6zgzXziZuKvUM= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h1:MD80ZRCTvxxJ8PBmhtrKoTnky8cVNYrCrIBLVRbrOM0= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 h1:YudTCEe/2xWdfPY/ESSiPFW4MVsrAoi2MWPwRUJ6QAA= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 h1:640M3TP06nBckEVqRZljcG/7AJlBxJ6vLXTHy6xCtwE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba h1:YNSlhK5mobyAaw02LPGgIEuS3lXyCTXcc6oaV2L6uUI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU= -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= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e h1:9ypZ/8aW8Vm497i1gXHcT96oNLiu88jbg9QdX+IUE3E= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= -github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= -github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= +github.com/smartcontractkit/wsrpc v0.7.3 h1:CKYZfawZShZGfvsQep1F9oBansnFk9ByZPCdTMpLphw= +github.com/smartcontractkit/wsrpc v0.7.3/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1434,6 +1430,7 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1667,7 +1664,6 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/integration-tests/README.md b/integration-tests/README.md index d34b4426fd8..fcfefe97a73 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -127,4 +127,4 @@ Run soak/ocr_test.go with RPC network chaos by bringing down network to RPC node ```bash make test_soak_ocr_rpc_down_half_cl_nodes -``` \ No newline at end of file +``` diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index bdca411c1d8..2763141a899 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -5,6 +5,7 @@ import ( "context" "crypto/ecdsa" "fmt" + "math" "math/big" "strings" "sync" @@ -40,7 +41,6 @@ import ( gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "github.com/test-go/testify/require" - "math" ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index 22220af9d63..9aa96040250 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -274,9 +274,12 @@ func DeployAutoOCRRegistryAndRegistrar( // DeployConsumers deploys and registers keeper consumers. If ephemeral addresses are enabled, it will deploy and register the consumers from ephemeral addresses, but each upkpeep will be registered with root key address as the admin. Which means // that functions like setting upkeep configuration, pausing, unpausing, etc. will be done by the root key address. It deploys multicall contract and sends link funds to each deployment address. -func DeployConsumers(t *testing.T, chainClient *seth.Client, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool, isMercury bool) ([]contracts.KeeperConsumer, []*big.Int) { - err := DeployMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep) - require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") +func DeployConsumers(t *testing.T, chainClient *seth.Client, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool, isMercury bool, isBillingTokenNative bool, wethToken contracts.WETHToken) ([]contracts.KeeperConsumer, []*big.Int) { + // Fund deployers with LINK, no need to do this for Native token + if !isBillingTokenNative { + err := DeployMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep) + require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") + } upkeeps := DeployKeeperConsumers(t, chainClient, numberOfUpkeeps, isLogTrigger, isMercury) require.Equal(t, numberOfUpkeeps, len(upkeeps), "Number of upkeeps should match") @@ -285,7 +288,7 @@ func DeployConsumers(t *testing.T, chainClient *seth.Client, registry contracts. upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } upkeepIds := RegisterUpkeepContracts( - t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, isLogTrigger, isMercury, + t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, isLogTrigger, isMercury, isBillingTokenNative, wethToken, ) require.Equal(t, numberOfUpkeeps, len(upkeepIds), "Number of upkeepIds should match") return upkeeps, upkeepIds @@ -318,7 +321,7 @@ func DeployPerformanceConsumers( for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false) + upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false, false, nil) return upkeeps, upkeepIds } @@ -344,7 +347,7 @@ func DeployPerformDataCheckerConsumers( for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false) + upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false, false, nil) return upkeeps, upkeepIds } diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go index 1ed4bef1414..f7d495bda5a 100644 --- a/integration-tests/actions/automationv2/actions.go +++ b/integration-tests/actions/automationv2/actions.go @@ -565,7 +565,8 @@ func (a *AutomationTest) SetConfigOnRegistry() error { } else if a.RegistrySettings.RegistryVersion == ethereum.RegistryVersion_2_3 { ocrConfig.TypedOnchainConfig23 = a.RegistrySettings.Create23OnchainConfig(a.Registrar.Address(), a.UpkeepPrivilegeManager, a.Registry.ChainModuleAddress(), a.Registry.ReorgProtectionEnabled()) ocrConfig.BillingTokens = []common.Address{ - common.HexToAddress(a.LinkToken.Address()), // TODO add more billing tokens + common.HexToAddress(a.LinkToken.Address()), + common.HexToAddress(a.WETHToken.Address()), } ocrConfig.BillingConfigs = []i_automation_registry_master_wrapper_2_3.AutomationRegistryBase23BillingConfig{ @@ -577,6 +578,14 @@ func (a *AutomationTest) SetConfigOnRegistry() error { FallbackPrice: big.NewInt(1000), MinSpend: big.NewInt(200), }, + { + GasFeePPB: 100, + FlatFeeMilliCents: big.NewInt(500), + PriceFeed: common.HexToAddress(a.EthUSDFeed.Address()), // ETH/USD feed and LINK/USD feed are the same + Decimals: 18, + FallbackPrice: big.NewInt(1000), + MinSpend: big.NewInt(200), + }, } } err = a.Registry.SetConfigTypeSafe(ocrConfig) diff --git a/integration-tests/actions/keeper_helpers.go b/integration-tests/actions/keeper_helpers.go index 7f02f54c751..ee1662cc180 100644 --- a/integration-tests/actions/keeper_helpers.go +++ b/integration-tests/actions/keeper_helpers.go @@ -8,6 +8,7 @@ import ( "strconv" "testing" + "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" "github.com/pkg/errors" "github.com/smartcontractkit/seth" @@ -115,7 +116,7 @@ func DeployKeeperContracts( } registrar := DeployKeeperRegistrar(t, client, registryVersion, linkToken, registrarSettings, registry) - upkeeps, upkeepIds := DeployConsumers(t, client, registry, registrar, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, upkeepGasLimit, false, false) + upkeeps, upkeepIds := DeployConsumers(t, client, registry, registrar, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, upkeepGasLimit, false, false, false, nil) return registry, registrar, upkeeps, upkeepIds } @@ -178,7 +179,7 @@ func DeployPerformanceKeeperContracts( upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false) + upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false, false, nil) return registry, registrar, upkeeps, upkeepIds } @@ -236,7 +237,7 @@ func DeployPerformDataCheckerContracts( upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false) + upkeepIds := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false, false, nil) return registry, registrar, upkeeps, upkeepIds } @@ -259,14 +260,14 @@ func DeployKeeperRegistrar( return registrar } -func RegisterUpkeepContracts(t *testing.T, client *seth.Client, linkToken contracts.LinkToken, linkFunds *big.Int, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, isLogTrigger bool, isMercury bool) []*big.Int { +func RegisterUpkeepContracts(t *testing.T, client *seth.Client, linkToken contracts.LinkToken, fundsForEachUpkeep *big.Int, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, isLogTrigger bool, isMercury bool, isBillingTokenNative bool, wethToken contracts.WETHToken) []*big.Int { checkData := make([][]byte, 0) for i := 0; i < numberOfContracts; i++ { checkData = append(checkData, []byte("0")) } return RegisterUpkeepContractsWithCheckData( - t, client, linkToken, linkFunds, upkeepGasLimit, registry, registrar, - numberOfContracts, upkeepAddresses, checkData, isLogTrigger, isMercury) + t, client, linkToken, fundsForEachUpkeep, upkeepGasLimit, registry, registrar, + numberOfContracts, upkeepAddresses, checkData, isLogTrigger, isMercury, isBillingTokenNative, wethToken) } type upkeepRegistrationResult struct { @@ -284,7 +285,7 @@ type upkeepConfig struct { type UpkeepId = *big.Int -func RegisterUpkeepContractsWithCheckData(t *testing.T, client *seth.Client, linkToken contracts.LinkToken, linkFunds *big.Int, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, checkData [][]byte, isLogTrigger bool, isMercury bool) []*big.Int { +func RegisterUpkeepContractsWithCheckData(t *testing.T, client *seth.Client, linkToken contracts.LinkToken, fundsForEachUpkeep *big.Int, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, checkData [][]byte, isLogTrigger bool, isMercury bool, isBillingTokenNative bool, wethToken contracts.WETHToken) []*big.Int { l := logging.GetTestLogger(t) concurrency, err := GetAndAssertCorrectConcurrency(client, 1) @@ -300,45 +301,69 @@ func RegisterUpkeepContractsWithCheckData(t *testing.T, client *seth.Client, lin var registerUpkeepFn = func(resultCh chan upkeepRegistrationResult, errorCh chan error, executorNum int, config upkeepConfig) { id := uuid.New().String() keyNum := executorNum + 1 // key 0 is the root key + var tx *types.Transaction + + if isBillingTokenNative { + // register upkeep with native token + tx, err = registrar.RegisterUpkeepFromKey( + keyNum, + fmt.Sprintf("upkeep_%s", id), + []byte("test@mail.com"), + config.address, + upkeepGasLimit, + client.MustGetRootKeyAddress().Hex(), // upkeep Admin + config.data, + fundsForEachUpkeep, + wethToken.Address(), + isLogTrigger, + isMercury, + ) + if err != nil { + errorCh <- errors.Wrapf(err, "[id: %s] Failed to register upkeep at %s", id, config.address) + return + } + } else { + // register upkeep with LINK + req, err := registrar.EncodeRegisterRequest( + fmt.Sprintf("upkeep_%s", id), + []byte("test@mail.com"), + config.address, + upkeepGasLimit, + client.MustGetRootKeyAddress().Hex(), // upkeep Admin + config.data, + fundsForEachUpkeep, + 0, + client.Addresses[keyNum].Hex(), + isLogTrigger, + isMercury, + linkToken.Address(), + ) + + if err != nil { + errorCh <- errors.Wrapf(err, "[id: %s] Failed to encode register request for upkeep at %s", id, config.address) + return + } - req, err := registrar.EncodeRegisterRequest( - fmt.Sprintf("upkeep_%s", id), - []byte("test@mail.com"), - config.address, - upkeepGasLimit, - client.MustGetRootKeyAddress().Hex(), // upkeep Admin - config.data, - linkFunds, - 0, - client.Addresses[keyNum].Hex(), - isLogTrigger, - isMercury, - linkToken.Address(), - ) - - if err != nil { - errorCh <- errors.Wrapf(err, "[id: %s] Failed to encode register request for upkeep at %s", id, config.address) - return - } - - balance, err := linkToken.BalanceOf(context.Background(), client.Addresses[keyNum].Hex()) - if err != nil { - errorCh <- errors.Wrapf(err, "[id: %s]Failed to get LINK balance of %s", id, client.Addresses[keyNum].Hex()) - return - } + balance, err := linkToken.BalanceOf(context.Background(), client.Addresses[keyNum].Hex()) + if err != nil { + errorCh <- errors.Wrapf(err, "[id: %s]Failed to get LINK balance of %s", id, client.Addresses[keyNum].Hex()) + return + } - // not stricly necessary, but helps us to avoid an errorless revert if there is not enough LINK - if balance.Cmp(linkFunds) < 0 { - errorCh <- fmt.Errorf("[id: %s] Not enough LINK balance for %s. Has: %s. Needs: %s", id, client.Addresses[keyNum].Hex(), balance.String(), linkFunds.String()) - return - } + // not strictly necessary, but helps us to avoid an errorless revert if there is not enough LINK + if balance.Cmp(fundsForEachUpkeep) < 0 { + errorCh <- fmt.Errorf("[id: %s] Not enough LINK balance for %s. Has: %s. Needs: %s", id, client.Addresses[keyNum].Hex(), balance.String(), fundsForEachUpkeep.String()) + return + } - tx, err := linkToken.TransferAndCallFromKey(registrar.Address(), linkFunds, req, keyNum) - if err != nil { - errorCh <- errors.Wrapf(err, "[id: %s] Failed to register upkeep at %s", id, config.address) - return + tx, err = linkToken.TransferAndCallFromKey(registrar.Address(), fundsForEachUpkeep, req, keyNum) + if err != nil { + errorCh <- errors.Wrapf(err, "[id: %s] Failed to register upkeep at %s", id, config.address) + return + } } + // parse txn to get upkeep ID receipt, err := client.Client.TransactionReceipt(context.Background(), tx.Hash()) if err != nil { errorCh <- errors.Wrapf(err, "[id: %s] Failed to get receipt for upkeep at %s and tx hash %s", id, config.address, tx.Hash()) @@ -405,10 +430,10 @@ func DeployKeeperConsumers(t *testing.T, client *seth.Client, numberOfContracts // v2.1 only: Conditional based contract with Mercury enabled keeperConsumerInstance, err = contracts.DeployAutomationStreamsLookupUpkeepConsumerFromKey(client, keyNum, big.NewInt(1000), big.NewInt(5), false, true, false) // 1000 block test range } else if isLogTrigger { - // v2.1 only: Log triggered based contract without Mercury + // v2.1+: Log triggered based contract without Mercury keeperConsumerInstance, err = contracts.DeployAutomationLogTriggerConsumerFromKey(client, keyNum, big.NewInt(1000)) // 1000 block test range } else { - // v2.0 and v2.1: Conditional based contract without Mercury + // v2.0+: Conditional based contract without Mercury keeperConsumerInstance, err = contracts.DeployUpkeepCounterFromKey(client, keyNum, big.NewInt(999999), big.NewInt(5)) } @@ -580,7 +605,7 @@ func RegisterNewUpkeeps( err = SendLinkFundsToDeploymentAddresses(chainClient, concurrency, numberOfNewUpkeeps, operationsPerAddress, multicallAddress, linkFundsForEachUpkeep, linkToken) require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") - newUpkeepIDs := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfNewUpkeeps, addressesOfNewUpkeeps, false, false) + newUpkeepIDs := RegisterUpkeepContracts(t, chainClient, linkToken, linkFundsForEachUpkeep, upkeepGasLimit, registry, registrar, numberOfNewUpkeeps, addressesOfNewUpkeeps, false, false, false, nil) return newlyDeployedUpkeeps, newUpkeepIDs } diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go deleted file mode 100644 index 58e394cb797..00000000000 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_config_helpers.go +++ /dev/null @@ -1,338 +0,0 @@ -package ocr2vrf_actions - -import ( - "crypto/ed25519" - "encoding/hex" - "errors" - "fmt" - "strconv" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/lib/pq" - "github.com/stretchr/testify/require" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/edwards25519" - "gopkg.in/guregu/null.v4" - - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink-vrf/altbn_128" - "github.com/smartcontractkit/chainlink-vrf/dkg" - "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" -) - -// CreateOCR2VRFJobs bootstraps the first node and to the other nodes sends ocr jobs -func CreateOCR2VRFJobs( - t *testing.T, - bootstrapNode *client.ChainlinkK8sClient, - nonBootstrapNodes []*client.ChainlinkK8sClient, - OCR2VRFPluginConfig *OCR2VRFPluginConfig, - chainID int64, - keyIndex int, -) { - l := logging.GetTestLogger(t) - p2pV2Bootstrapper := createBootstrapJob(t, bootstrapNode, OCR2VRFPluginConfig.DKGConfig.DKGContractAddress, chainID) - - createNonBootstrapJobs(t, nonBootstrapNodes, OCR2VRFPluginConfig, chainID, keyIndex, p2pV2Bootstrapper) - l.Info().Msg("Done creating OCR automation jobs") -} - -func createNonBootstrapJobs( - t *testing.T, - nonBootstrapNodes []*client.ChainlinkK8sClient, - OCR2VRFPluginConfig *OCR2VRFPluginConfig, - chainID int64, - keyIndex int, - P2Pv2Bootstrapper string, -) { - for index, nonBootstrapNode := range nonBootstrapNodes { - nodeTransmitterAddress, err := nonBootstrapNode.EthAddresses() - require.NoError(t, err, "Shouldn't fail getting primary ETH address from OCR node %d", index) - nodeOCRKeys, err := nonBootstrapNode.MustReadOCR2Keys() - require.NoError(t, err, "Shouldn't fail getting OCR keys from OCR node %d", index) - var nodeOCRKeyId []string - for _, key := range nodeOCRKeys.Data { - if key.Attributes.ChainType == string(chaintype.EVM) { - nodeOCRKeyId = append(nodeOCRKeyId, key.ID) - break - } - } - - OCR2VRFJobSpec := client.OCR2TaskJobSpec{ - Name: "ocr2", - JobType: "offchainreporting2", - OCR2OracleSpec: job.OCR2OracleSpec{ - PluginType: "ocr2vrf", - Relay: "evm", - RelayConfig: map[string]interface{}{ - "chainID": int(chainID), - }, - ContractID: OCR2VRFPluginConfig.VRFBeaconConfig.VRFBeaconAddress, - OCRKeyBundleID: null.StringFrom(nodeOCRKeyId[keyIndex]), - TransmitterID: null.StringFrom(nodeTransmitterAddress[keyIndex]), - P2PV2Bootstrappers: pq.StringArray{P2Pv2Bootstrapper}, - PluginConfig: map[string]interface{}{ - "dkgEncryptionPublicKey": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.DKGConfig.DKGKeyConfigs[index].DKGEncryptionPublicKey), - "dkgSigningPublicKey": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.DKGConfig.DKGKeyConfigs[index].DKGSigningPublicKey), - "dkgKeyID": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.DKGConfig.DKGKeyID), - "dkgContractAddress": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.DKGConfig.DKGContractAddress), - "vrfCoordinatorAddress": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.VRFCoordinatorAddress), - "linkEthFeedAddress": fmt.Sprintf("\"%s\"", OCR2VRFPluginConfig.LinkEthFeedAddress), - }, - }, - } - _, err = nonBootstrapNode.MustCreateJob(&OCR2VRFJobSpec) - require.NoError(t, err, "Shouldn't fail creating OCR Task job on OCR node %d", index) - } -} - -func createBootstrapJob(t *testing.T, bootstrapNode *client.ChainlinkK8sClient, dkgAddress string, chainID int64) string { - bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() - require.NoError(t, err, "Shouldn't fail reading P2P keys from bootstrap node") - bootstrapP2PId := bootstrapP2PIds.Data[0].Attributes.PeerID - - bootstrapSpec := &client.OCR2TaskJobSpec{ - Name: "ocr2 bootstrap node", - JobType: "bootstrap", - OCR2OracleSpec: job.OCR2OracleSpec{ - ContractID: dkgAddress, - Relay: "evm", - RelayConfig: map[string]interface{}{ - "chainID": int(chainID), - }, - }, - } - _, err = bootstrapNode.MustCreateJob(bootstrapSpec) - require.NoError(t, err, "Shouldn't fail creating bootstrap job on bootstrap node") - return fmt.Sprintf("%s@%s:%d", bootstrapP2PId, bootstrapNode.InternalIP(), 6690) -} - -func BuildOCR2DKGConfigVars( - t *testing.T, - ocr2VRFPluginConfig *OCR2VRFPluginConfig, -) contracts.OCRv2Config { - l := logging.GetTestLogger(t) - var onchainPublicKeys []common.Address - for _, onchainPublicKey := range ocr2VRFPluginConfig.OCR2Config.OnchainPublicKeys { - onchainPublicKeys = append(onchainPublicKeys, common.HexToAddress(onchainPublicKey)) - } - - var transmitters []common.Address - for _, transmitterAddress := range ocr2VRFPluginConfig.OCR2Config.TransmitterAddresses { - transmitters = append(transmitters, common.HexToAddress(transmitterAddress)) - } - oracleIdentities, err := toOraclesIdentityList( - onchainPublicKeys, - ocr2VRFPluginConfig.OCR2Config.OffchainPublicKeys, - ocr2VRFPluginConfig.OCR2Config.ConfigPublicKeys, - ocr2VRFPluginConfig.OCR2Config.PeerIds, - ocr2VRFPluginConfig.OCR2Config.TransmitterAddresses, - ) - require.NoError(t, err) - - ed25519Suite := edwards25519.NewBlakeSHA256Ed25519() - var signingKeys []kyber.Point - for _, dkgKey := range ocr2VRFPluginConfig.DKGConfig.DKGKeyConfigs { - signingKeyBytes, err := hex.DecodeString(dkgKey.DKGSigningPublicKey) - require.NoError(t, err) - signingKeyPoint := ed25519Suite.Point() - err = signingKeyPoint.UnmarshalBinary(signingKeyBytes) - require.NoError(t, err) - signingKeys = append(signingKeys, signingKeyPoint) - } - - altbn128Suite := &altbn_128.PairingSuite{} - var encryptionKeys []kyber.Point - for _, dkgKey := range ocr2VRFPluginConfig.DKGConfig.DKGKeyConfigs { - encryptionKeyBytes, err := hex.DecodeString(dkgKey.DKGEncryptionPublicKey) - require.NoError(t, err) - encryptionKeyPoint := altbn128Suite.G1().Point() - err = encryptionKeyPoint.UnmarshalBinary(encryptionKeyBytes) - require.NoError(t, err) - encryptionKeys = append(encryptionKeys, encryptionKeyPoint) - } - - keyIDBytes, err := DecodeHexTo32ByteArray(ocr2VRFPluginConfig.DKGConfig.DKGKeyID) - require.NoError(t, err, "Shouldn't fail decoding DKG key ID") - - offchainConfig, err := dkg.OffchainConfig(encryptionKeys, signingKeys, &altbn_128.G1{}, &ocr2vrftypes.PairingTranslation{ - Suite: &altbn_128.PairingSuite{}, - }) - require.NoError(t, err) - onchainConfig, err := dkg.OnchainConfig(dkg.KeyID(keyIDBytes)) - require.NoError(t, err) - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := - confighelper.ContractSetConfigArgsForTests( - 30*time.Second, // deltaProgress time.Duration, - 10*time.Second, // deltaResend time.Duration, - 10*time.Millisecond, // deltaRound time.Duration, - 20*time.Millisecond, // deltaGrace time.Duration, - 20*time.Millisecond, // deltaStage time.Duration, - 3, // rMax uint8, - ocr2VRFPluginConfig.OCR2Config.Schedule, // s []int, - oracleIdentities, // oracles []OracleIdentityExtra, - offchainConfig, - 10*time.Millisecond, // maxDurationQuery time.Duration, - 10*time.Second, // maxDurationObservation time.Duration, - 10*time.Second, // maxDurationReport time.Duration, - 10*time.Millisecond, // maxDurationShouldAcceptFinalizedReport time.Duration, - 1*time.Second, // maxDurationShouldTransmitAcceptedReport time.Duration, - 1, // f int, - onchainConfig, // onchainConfig []byte, - ) - require.NoError(t, err, "Shouldn't fail building OCR config") - - l.Info().Msg("Done building DKG OCR config") - return contracts.OCRv2Config{ - Signers: onchainPublicKeys, - Transmitters: transmitters, - F: f, - OnchainConfig: onchainConfig, - OffchainConfigVersion: offchainConfigVersion, - OffchainConfig: offchainConfig, - } -} - -func toOraclesIdentityList( - onchainPubKeys []common.Address, - offchainPubKeys, - configPubKeys, - peerIDs, - transmitters []string, -) ([]confighelper.OracleIdentityExtra, error) { - offchainPubKeysBytes := []types.OffchainPublicKey{} - for _, pkHex := range offchainPubKeys { - pkBytes, err := hex.DecodeString(pkHex) - if err != nil { - return nil, err - } - pkBytesFixed := [ed25519.PublicKeySize]byte{} - n := copy(pkBytesFixed[:], pkBytes) - if n != ed25519.PublicKeySize { - return nil, errors.New("wrong num elements copied") - } - - offchainPubKeysBytes = append(offchainPubKeysBytes, types.OffchainPublicKey(pkBytesFixed)) - } - - configPubKeysBytes := []types.ConfigEncryptionPublicKey{} - for _, pkHex := range configPubKeys { - pkBytes, err := hex.DecodeString(pkHex) - if err != nil { - return nil, err - } - pkBytesFixed := [ed25519.PublicKeySize]byte{} - n := copy(pkBytesFixed[:], pkBytes) - if n != ed25519.PublicKeySize { - return nil, errors.New("wrong num elements copied") - } - - configPubKeysBytes = append(configPubKeysBytes, types.ConfigEncryptionPublicKey(pkBytesFixed)) - } - - o := []confighelper.OracleIdentityExtra{} - for index := range configPubKeys { - o = append(o, confighelper.OracleIdentityExtra{ - OracleIdentity: confighelper.OracleIdentity{ - OnchainPublicKey: onchainPubKeys[index][:], - OffchainPublicKey: offchainPubKeysBytes[index], - PeerID: peerIDs[index], - TransmitAccount: types.Account(transmitters[index]), - }, - ConfigEncryptionPublicKey: configPubKeysBytes[index], - }) - } - return o, nil -} - -func DecodeHexTo32ByteArray(val string) ([32]byte, error) { - var byteArray [32]byte - decoded, err := hex.DecodeString(val) - if err != nil { - return [32]byte{}, err - } - if len(decoded) != 32 { - return [32]byte{}, fmt.Errorf("expected value to be 32 bytes but received %d bytes", len(decoded)) - } - copy(byteArray[:], decoded) - return byteArray, err -} - -func BuildOCR2VRFConfigVars( - t *testing.T, - ocr2VRFPluginConfig *OCR2VRFPluginConfig, -) contracts.OCRv2Config { - l := logging.GetTestLogger(t) - var onchainPublicKeys []common.Address - for _, onchainPublicKey := range ocr2VRFPluginConfig.OCR2Config.OnchainPublicKeys { - onchainPublicKeys = append(onchainPublicKeys, common.HexToAddress(onchainPublicKey)) - } - - var transmitters []common.Address - for _, transmitterAddress := range ocr2VRFPluginConfig.OCR2Config.TransmitterAddresses { - transmitters = append(transmitters, common.HexToAddress(transmitterAddress)) - } - - oracleIdentities, err := toOraclesIdentityList( - onchainPublicKeys, - ocr2VRFPluginConfig.OCR2Config.OffchainPublicKeys, - ocr2VRFPluginConfig.OCR2Config.ConfigPublicKeys, - ocr2VRFPluginConfig.OCR2Config.PeerIds, - ocr2VRFPluginConfig.OCR2Config.TransmitterAddresses, - ) - require.NoError(t, err) - - confDelays := make(map[uint32]struct{}) - - for _, c := range ocr2VRFPluginConfig.VRFBeaconConfig.ConfDelays { - confDelay, err := strconv.ParseUint(c, 0, 32) - require.NoError(t, err) - confDelays[uint32(confDelay)] = struct{}{} - } - - onchainConfig := ocr2vrf.OnchainConfig(confDelays) - - _, _, f, onchainConfig, offchainConfigVersion, offchainConfig, err := - confighelper.ContractSetConfigArgsForTests( - 30*time.Second, // deltaProgress time.Duration, - 10*time.Second, // deltaResend time.Duration, - 10*time.Second, // deltaRound time.Duration, - 20*time.Second, // deltaGrace time.Duration, - 20*time.Second, // deltaStage time.Duration, - 3, // rMax uint8, - ocr2VRFPluginConfig.OCR2Config.Schedule, // s []int, - oracleIdentities, // oracles []OracleIdentityExtra, - ocr2vrf.OffchainConfig(ocr2VRFPluginConfig.VRFBeaconConfig.CoordinatorConfig), - 10*time.Millisecond, // maxDurationQuery time.Duration, - 10*time.Second, // maxDurationObservation time.Duration, - 10*time.Second, // maxDurationReport time.Duration, - 5*time.Second, // maxDurationShouldAcceptFinalizedReport time.Duration, - 1*time.Second, // maxDurationShouldTransmitAcceptedReport time.Duration, - 1, // f int, - onchainConfig, // onchainConfig []byte, - ) - require.NoError(t, err) - - l.Info().Msg("Done building VRF OCR config") - return contracts.OCRv2Config{ - Signers: onchainPublicKeys, - Transmitters: transmitters, - F: f, - OnchainConfig: onchainConfig, - OffchainConfigVersion: offchainConfigVersion, - OffchainConfig: offchainConfig, - } - -} diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go deleted file mode 100644 index 7f17be3fd84..00000000000 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants/ocr2vrf_constants.go +++ /dev/null @@ -1,31 +0,0 @@ -package ocr2vrf_constants - -import ( - "math/big" - "time" - - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" -) - -var ( - LinkEthFeedResponse = big.NewInt(1e18) - LinkFundingAmount = big.NewInt(100) - BeaconPeriodBlocksCount = big.NewInt(3) - EthFundingAmount = big.NewFloat(1) - NumberOfRandomWordsToRequest = uint16(2) - ConfirmationDelay = big.NewInt(1) - RandomnessFulfilmentTransmissionEventTimeout = time.Minute * 6 - RandomnessRedeemTransmissionEventTimeout = time.Minute * 5 - //keyId can be any random value - KeyID = "aee00d81f822f882b6fe28489822f59ebb21ea95c0ae21d9f67c0239461148fc" - - CoordinatorConfig = &ocr2vrftypes.CoordinatorConfig{ - CacheEvictionWindowSeconds: 60, - BatchGasLimit: 5_000_000, - CoordinatorOverhead: 50_000, - CallbackOverhead: 50_000, - BlockGasOverhead: 50_000, - LookbackBlocks: 1_000, - } - VRFBeaconAllowedConfirmationDelays = []string{"1", "2", "3", "4", "5", "6", "7", "8"} -) diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go deleted file mode 100644 index 08580203380..00000000000 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_models.go +++ /dev/null @@ -1,37 +0,0 @@ -package ocr2vrf_actions - -import ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - -type DKGKeyConfig struct { - DKGEncryptionPublicKey string - DKGSigningPublicKey string -} - -type DKGConfig struct { - DKGKeyConfigs []DKGKeyConfig - DKGKeyID string - DKGContractAddress string -} - -type VRFBeaconConfig struct { - VRFBeaconAddress string - ConfDelays []string - CoordinatorConfig *ocr2vrftypes.CoordinatorConfig -} - -type OCR2Config struct { - OnchainPublicKeys []string - OffchainPublicKeys []string - PeerIds []string - ConfigPublicKeys []string - TransmitterAddresses []string - Schedule []int -} - -type OCR2VRFPluginConfig struct { - OCR2Config OCR2Config - DKGConfig DKGConfig - VRFBeaconConfig VRFBeaconConfig - VRFCoordinatorAddress string - LinkEthFeedAddress string -} diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go deleted file mode 100644 index cda6fa72ca2..00000000000 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ /dev/null @@ -1,363 +0,0 @@ -package ocr2vrf_actions - -import ( - "math/big" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/seth" - - ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - - "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" -) - -func SetAndWaitForVRFBeaconProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, vrfBeacon contracts.VRFBeacon) { - l := logging.GetTestLogger(t) - ocr2VrfConfig := BuildOCR2VRFConfigVars(t, ocr2VRFPluginConfig) - l.Debug().Interface("OCR2 VRF Config", ocr2VrfConfig).Msg("OCR2 VRF Config prepared") - - err := vrfBeacon.SetConfig( - ocr2VrfConfig.Signers, - ocr2VrfConfig.Transmitters, - ocr2VrfConfig.F, - ocr2VrfConfig.OnchainConfig, - ocr2VrfConfig.OffchainConfigVersion, - ocr2VrfConfig.OffchainConfig, - ) - require.NoError(t, err, "Error setting OCR config for VRFBeacon contract") - - vrfConfigSetEvent, err := vrfBeacon.WaitForConfigSetEvent(time.Minute) - require.NoError(t, err, "Error waiting for ConfigSet Event for VRFBeacon contract") - l.Info().Interface("Event", vrfConfigSetEvent).Msg("OCR2 VRF Config was set") -} - -func SetAndWaitForDKGProcessToFinish(t *testing.T, ocr2VRFPluginConfig *OCR2VRFPluginConfig, dkg contracts.DKG) { - l := logging.GetTestLogger(t) - ocr2DkgConfig := BuildOCR2DKGConfigVars(t, ocr2VRFPluginConfig) - - // set config for DKG OCR - l.Debug().Interface("OCR2 DKG Config", ocr2DkgConfig).Msg("OCR2 DKG Config prepared") - err := dkg.SetConfig( - ocr2DkgConfig.Signers, - ocr2DkgConfig.Transmitters, - ocr2DkgConfig.F, - ocr2DkgConfig.OnchainConfig, - ocr2DkgConfig.OffchainConfigVersion, - ocr2DkgConfig.OffchainConfig, - ) - require.NoError(t, err, "Error setting OCR config for DKG contract") - - // wait for the event ConfigSet from DKG contract - dkgConfigSetEvent, err := dkg.WaitForConfigSetEvent(time.Minute) - require.NoError(t, err, "Error waiting for ConfigSet Event for DKG contract") - l.Info().Interface("Event", dkgConfigSetEvent).Msg("OCR2 DKG Config Set") - // wait for the event Transmitted from DKG contract, meaning that OCR committee has sent out the Public key and Shares - dkgSharesTransmittedEvent, err := dkg.WaitForTransmittedEvent(time.Minute * 5) - require.NoError(t, err) - l.Info().Interface("Event", dkgSharesTransmittedEvent).Msg("DKG Shares were generated and transmitted by OCR Committee") -} - -func SetAndGetOCR2VRFPluginConfig( - t *testing.T, - nonBootstrapNodes []*client.ChainlinkK8sClient, - dkg contracts.DKG, - vrfBeacon contracts.VRFBeacon, - coordinator contracts.VRFCoordinatorV3, - mockETHLinkFeed contracts.MockETHLINKFeed, - keyID string, - vrfBeaconAllowedConfirmationDelays []string, - coordinatorConfig *ocr2vrftypes.CoordinatorConfig, -) *OCR2VRFPluginConfig { - var ( - dkgKeyConfigs []DKGKeyConfig - transmitters []string - ocrConfigPubKeys []string - peerIDs []string - ocrOnchainPubKeys []string - ocrOffchainPubKeys []string - schedule []int - ) - - for _, node := range nonBootstrapNodes { - dkgSignKey, err := node.MustCreateDkgSignKey() - require.NoError(t, err, "Error creating DKG Sign Keys") - - dkgEncryptKey, err := node.MustCreateDkgEncryptKey() - require.NoError(t, err, "Error creating DKG Encrypt Keys") - - ethKeys, err := node.MustReadETHKeys() - require.NoError(t, err) - for _, key := range ethKeys.Data { - transmitters = append(transmitters, key.Attributes.Address) - } - - p2pKeys, err := node.MustReadP2PKeys() - require.NoError(t, err, "Shouldn't fail reading P2P keys from node") - - peerId := p2pKeys.Data[0].Attributes.PeerID - peerIDs = append(peerIDs, peerId) - - ocr2Keys, err := node.MustReadOCR2Keys() - require.NoError(t, err, "Shouldn't fail reading OCR2 keys from node") - var ocr2Config client.OCR2KeyAttributes - for _, key := range ocr2Keys.Data { - if key.Attributes.ChainType == string(chaintype.EVM) { - ocr2Config = key.Attributes - break - } - } - - offchainPubKey := strings.TrimPrefix(ocr2Config.OffChainPublicKey, "ocr2off_evm_") - ocrOffchainPubKeys = append(ocrOffchainPubKeys, offchainPubKey) - - configPubKey := strings.TrimPrefix(ocr2Config.ConfigPublicKey, "ocr2cfg_evm_") - ocrConfigPubKeys = append(ocrConfigPubKeys, configPubKey) - - onchainPubKey := strings.TrimPrefix(ocr2Config.OnChainPublicKey, "ocr2on_evm_") - ocrOnchainPubKeys = append(ocrOnchainPubKeys, onchainPubKey) - - schedule = append(schedule, 1) - - dkgKeyConfigs = append(dkgKeyConfigs, DKGKeyConfig{ - DKGEncryptionPublicKey: dkgEncryptKey.Data.Attributes.PublicKey, - DKGSigningPublicKey: dkgSignKey.Data.Attributes.PublicKey, - }) - } - - ocr2VRFPluginConfig := &OCR2VRFPluginConfig{ - OCR2Config: OCR2Config{ - OnchainPublicKeys: ocrOnchainPubKeys, - OffchainPublicKeys: ocrOffchainPubKeys, - ConfigPublicKeys: ocrConfigPubKeys, - PeerIds: peerIDs, - TransmitterAddresses: transmitters, - Schedule: schedule, - }, - - DKGConfig: DKGConfig{ - DKGKeyConfigs: dkgKeyConfigs, - DKGKeyID: keyID, - DKGContractAddress: dkg.Address(), - }, - VRFBeaconConfig: VRFBeaconConfig{ - VRFBeaconAddress: vrfBeacon.Address(), - ConfDelays: vrfBeaconAllowedConfirmationDelays, - CoordinatorConfig: coordinatorConfig, - }, - VRFCoordinatorAddress: coordinator.Address(), - LinkEthFeedAddress: mockETHLinkFeed.Address(), - } - return ocr2VRFPluginConfig -} - -func FundVRFCoordinatorV3Subscription(t *testing.T, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV3, subscriptionID, linkFundingAmount *big.Int) { - encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) - require.NoError(t, err, "Error Abi encoding subscriptionID") - _, err = linkToken.TransferAndCall(coordinator.Address(), big.NewInt(0).Mul(linkFundingAmount, big.NewInt(1e18)), encodedSubId) - require.NoError(t, err, "Error sending Link token") -} - -func DeployOCR2VRFContracts(t *testing.T, chainClient *seth.Client, linkToken contracts.LinkToken, beaconPeriodBlocksCount *big.Int, keyID string) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer) { - dkg, err := contracts.DeployDKG(chainClient) - require.NoError(t, err, "Error deploying DKG Contract") - - coordinator, err := contracts.DeployOCR2VRFCoordinator(chainClient, beaconPeriodBlocksCount, linkToken.Address()) - require.NoError(t, err, "Error deploying OCR2VRFCoordinator Contract") - - vrfBeacon, err := contracts.DeployVRFBeacon(chainClient, coordinator.Address(), linkToken.Address(), dkg.Address(), keyID) - require.NoError(t, err, "Error deploying VRFBeacon Contract") - - consumer, err := contracts.DeployVRFBeaconConsumer(chainClient, coordinator.Address(), beaconPeriodBlocksCount) - require.NoError(t, err, "Error deploying VRFBeaconConsumer Contract") - - return dkg, coordinator, vrfBeacon, consumer -} - -func RequestAndRedeemRandomness( - t *testing.T, - consumer contracts.VRFBeaconConsumer, - vrfBeacon contracts.VRFBeacon, - numberOfRandomWordsToRequest uint16, - subscriptionID, - confirmationDelay *big.Int, - randomnessTransmissionEventTimeout time.Duration, -) *big.Int { - l := logging.GetTestLogger(t) - receipt, err := consumer.RequestRandomness( - numberOfRandomWordsToRequest, - subscriptionID, - confirmationDelay, - ) - require.NoError(t, err, "Error requesting randomness from Consumer Contract") - l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness requested from Consumer contract") - - requestID := getRequestId(t, consumer, receipt, confirmationDelay) - - newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout) - require.NoError(t, err, "Error waiting for NewTransmission event from VRF Beacon Contract") - l.Info().Interface("NewTransmission event", newTransmissionEvent).Msg("Randomness transmitted by DON") - - err = consumer.RedeemRandomness(subscriptionID, requestID) - require.NoError(t, err, "Error redeeming randomness from Consumer Contract") - - return requestID -} - -func RequestRandomnessFulfillmentAndWaitForFulfilment( - t *testing.T, - consumer contracts.VRFBeaconConsumer, - vrfBeacon contracts.VRFBeacon, - numberOfRandomWordsToRequest uint16, - subscriptionID *big.Int, - confirmationDelay *big.Int, - randomnessTransmissionEventTimeout time.Duration, -) *big.Int { - l := logging.GetTestLogger(t) - receipt, err := consumer.RequestRandomnessFulfillment( - numberOfRandomWordsToRequest, - subscriptionID, - confirmationDelay, - 200_000, - 100_000, - nil, - ) - require.NoError(t, err, "Error requesting Randomness Fulfillment") - l.Info().Interface("TX Hash", receipt.TxHash).Msg("Randomness Fulfillment requested from Consumer contract") - - requestID := getRequestId(t, consumer, receipt, confirmationDelay) - - newTransmissionEvent, err := vrfBeacon.WaitForNewTransmissionEvent(randomnessTransmissionEventTimeout) - require.NoError(t, err, "Error waiting for NewTransmission event from VRF Beacon Contract") - l.Info().Interface("NewTransmission event", newTransmissionEvent).Msg("Randomness Fulfillment transmitted by DON") - - return requestID -} - -func getRequestId(t *testing.T, consumer contracts.VRFBeaconConsumer, receipt *types.Receipt, confirmationDelay *big.Int) *big.Int { - periodBlocks, err := consumer.IBeaconPeriodBlocks(testcontext.Get(t)) - require.NoError(t, err, "Error getting Beacon Period block count") - - blockNumber := receipt.BlockNumber - periodOffset := new(big.Int).Mod(blockNumber, periodBlocks) - nextBeaconOutputHeight := new(big.Int).Sub(new(big.Int).Add(blockNumber, periodBlocks), periodOffset) - - requestID, err := consumer.GetRequestIdsBy(testcontext.Get(t), nextBeaconOutputHeight, confirmationDelay) - require.NoError(t, err, "Error getting requestID from consumer contract") - - return requestID -} - -func SetupOCR2VRFUniverse( - t *testing.T, - linkToken contracts.LinkToken, - mockETHLinkFeed contracts.MockETHLINKFeed, - chainClient *seth.Client, - nodeAddresses []common.Address, - chainlinkNodes []*client.ChainlinkK8sClient, - testNetwork blockchain.EVMNetwork, -) (contracts.DKG, contracts.VRFCoordinatorV3, contracts.VRFBeacon, contracts.VRFBeaconConsumer, *big.Int) { - l := logging.GetTestLogger(t) - - // Deploy DKG contract - // Deploy VRFCoordinator(beaconPeriodBlocks, linkAddress, linkEthfeedAddress) - // Deploy VRFBeacon - // Deploy Consumer Contract - dkgContract, coordinatorContract, vrfBeaconContract, consumerContract := DeployOCR2VRFContracts( - t, - chainClient, - linkToken, - ocr2vrf_constants.BeaconPeriodBlocksCount, - ocr2vrf_constants.KeyID, - ) - - // Add VRFBeacon as DKG client - err := dkgContract.AddClient(ocr2vrf_constants.KeyID, vrfBeaconContract.Address()) - require.NoError(t, err, "Error adding client to DKG Contract") - // Adding VRFBeacon as producer in VRFCoordinator - err = coordinatorContract.SetProducer(vrfBeaconContract.Address()) - require.NoError(t, err, "Error setting Producer for VRFCoordinator contract") - err = coordinatorContract.SetConfig(2.5e6, 160 /* 5 EVM words */) - require.NoError(t, err, "Error setting config for VRFCoordinator contract") - - // Subscription: - //1. Create Subscription - err = coordinatorContract.CreateSubscription() - require.NoError(t, err, "Error creating subscription in VRFCoordinator contract") - subID, err := coordinatorContract.FindSubscriptionID() - require.NoError(t, err) - - //2. Add Consumer to subscription - err = coordinatorContract.AddConsumer(subID, consumerContract.Address()) - require.NoError(t, err, "Error adding a consumer to a subscription in VRFCoordinator contract") - - //3. fund subscription with LINK token - FundVRFCoordinatorV3Subscription( - t, - linkToken, - coordinatorContract, - subID, - ocr2vrf_constants.LinkFundingAmount, - ) - - // set Payees for VRFBeacon ((address which gets the reward) for each transmitter) - nonBootstrapNodeAddresses := nodeAddresses[1:] - err = vrfBeaconContract.SetPayees(nonBootstrapNodeAddresses, nonBootstrapNodeAddresses) - require.NoError(t, err, "Error setting Payees in VRFBeacon Contract") - - // fund OCR Nodes (so that they can transmit) - nodes := contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes) - err = actions.FundChainlinkNodesFromRootAddress(l, chainClient, nodes, ocr2vrf_constants.EthFundingAmount) - require.NoError(t, err, "Error funding Nodes") - - bootstrapNode := chainlinkNodes[0] - nonBootstrapNodes := chainlinkNodes[1:] - - // Create DKG Sign and Encrypt keys for each non-bootstrap node - // set Job specs for each node - ocr2VRFPluginConfig := SetAndGetOCR2VRFPluginConfig( - t, - nonBootstrapNodes, - dkgContract, - vrfBeaconContract, - coordinatorContract, - mockETHLinkFeed, - ocr2vrf_constants.KeyID, - ocr2vrf_constants.VRFBeaconAllowedConfirmationDelays, - ocr2vrf_constants.CoordinatorConfig, - ) - // Create Jobs for Bootstrap and non-boostrap nodes - CreateOCR2VRFJobs( - t, - bootstrapNode, - nonBootstrapNodes, - ocr2VRFPluginConfig, - testNetwork.ChainID, - 0, - ) - - // set config for DKG OCR, - // wait for the event ConfigSet from DKG contract - // wait for the event Transmitted from DKG contract, meaning that OCR committee has sent out the Public key and Shares - SetAndWaitForDKGProcessToFinish(t, ocr2VRFPluginConfig, dkgContract) - - // set config for VRFBeacon OCR, - // wait for the event ConfigSet from VRFBeacon contract - SetAndWaitForVRFBeaconProcessToFinish(t, ocr2VRFPluginConfig, vrfBeaconContract) - return dkgContract, coordinatorContract, vrfBeaconContract, consumerContract, subID -} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 8c1d5bdac38..177b3521013 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -102,7 +102,7 @@ func TestAutomationBenchmark(t *testing.T) { testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err, "Error getting test type") - config, err := tc.GetConfig(testType, tc.Keeper) + config, err := tc.GetConfig([]string{testType}, tc.Keeper) require.NoError(t, err, "Error getting test config") testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t, &config) @@ -308,7 +308,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenc TTL: time.Hour * 720, // 30 days, NamespacePrefix: fmt.Sprintf( "automation-%s-%s-%s", - strings.ToLower(keeperTestConfig.GetConfigurationName()), + strings.ToLower(strings.Join(keeperTestConfig.GetConfigurationNames(), "")), strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), strings.ReplaceAll(strings.ToLower(*keeperTestConfig.GetKeeperConfig().Common.RegistryToTest), "_", "-"), ), @@ -318,7 +318,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenc dbResources := performanceDbResources chainlinkResources := performanceChainlinkResources - if strings.ToLower(keeperTestConfig.GetConfigurationName()) == "soak" { + if strings.Contains(strings.ToLower(strings.Join(keeperTestConfig.GetConfigurationNames(), ",")), "soak") { chainlinkResources = soakChainlinkResources dbResources = soakDbResources } diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index a6267138d21..e14c35ed17b 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -134,7 +134,7 @@ func TestAutomationChaos(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - config, err := tc.GetConfig("Chaos", tc.Automation) + config, err := tc.GetConfig([]string{"Chaos"}, tc.Automation) if err != nil { t.Fatal(err) } @@ -286,8 +286,8 @@ func TestAutomationChaos(t *testing.T) { } require.NoError(t, err, "Error setting OCR config") - consumersConditional, upkeepidsConditional := actions.DeployConsumers(t, chainClient, registry, registrar, linkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false, false) - consumersLogtrigger, upkeepidsLogtrigger := actions.DeployConsumers(t, chainClient, registry, registrar, linkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, true, false) + consumersConditional, upkeepidsConditional := actions.DeployConsumers(t, chainClient, registry, registrar, linkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false, false, false, nil) + consumersLogtrigger, upkeepidsLogtrigger := actions.DeployConsumers(t, chainClient, registry, registrar, linkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, true, false, false, nil) consumers := append(consumersConditional, consumersLogtrigger...) upkeepIDs := append(upkeepidsConditional, upkeepidsLogtrigger...) diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go deleted file mode 100644 index 95b8373dc20..00000000000 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package chaos - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" - seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" - "github.com/smartcontractkit/chainlink/integration-tests/client" - tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" -) - -func TestOCR2VRFChaos(t *testing.T) { - t.Parallel() - l := logging.GetTestLogger(t) - testConfig, err := tc.GetConfig("Chaos", tc.OCR2VRF) - if err != nil { - t.Fatal(err) - } - - loadedNetwork := networks.MustGetSelectedNetworkConfig(testConfig.Network)[0] - - tomlConfig, err := actions.BuildTOMLNodeConfigForK8s(&testConfig, loadedNetwork) - require.NoError(t, err, "Error building TOML config") - - defaultOCR2VRFSettings := map[string]interface{}{ - "replicas": 6, - "toml": tomlConfig, - } - - defaultOCR2VRFEthereumSettings := ðereum.Props{ - NetworkName: loadedNetwork.Name, - Simulated: loadedNetwork.Simulated, - WsURLs: loadedNetwork.URLs, - } - - var overrideFn = func(_ interface{}, target interface{}) { - ctf_config.MustConfigOverrideChainlinkVersion(testConfig.GetChainlinkImageConfig(), target) - ctf_config.MightConfigOverridePyroscopeKey(testConfig.GetPyroscopeConfig(), target) - } - - chainlinkCfg := chainlink.NewWithOverride(0, defaultOCR2VRFSettings, testConfig.ChainlinkImage, overrideFn) - - testCases := map[string]struct { - networkChart environment.ConnectedChart - clChart environment.ConnectedChart - chaosFunc chaos.ManifestFunc - chaosProps *chaos.Props - }{ - // network-* and pods-* are split intentionally into 2 parallel groups - // we can't use chaos.NewNetworkPartition and chaos.NewFailPods in parallel - // because of jsii runtime bug, see Makefile - - // PodChaosFailMinorityNodes Test description: - //1. DKG and VRF beacon processes are set and VRF request gets fulfilled - //2. Apply chaos experiment - take down 2 nodes out of 5 non-bootstrap - //3. Bring back all nodes to normal - //4. verify VRF request gets fulfilled - PodChaosFailMinorityNodes: { - ethereum.New(defaultOCR2VRFEthereumSettings), - chainlinkCfg, - chaos.NewFailPods, - &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, - DurationStr: "1m", - }, - }, - //todo - currently failing, need to investigate deeper - //PodChaosFailMajorityNodes: { - // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlinkCfg, - // chaos.NewFailPods, - // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, - // DurationStr: "1m", - // }, - //}, - //todo - do we need these chaos tests? - //PodChaosFailMajorityDB: { - // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlinkCfg, - // chaos.NewFailPods, - // &chaos.Props{ - // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, - // DurationStr: "1m", - // ContainerNames: &[]*string{ptr.Ptr("chainlink-db")}, - // }, - //}, - //NetworkChaosFailMajorityNetwork: { - // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlinkCfg, - // chaos.NewNetworkPartition, - // &chaos.Props{ - // FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, - // ToLabels: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, - // DurationStr: "1m", - // }, - //}, - //NetworkChaosFailBlockchainNode: { - // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlinkCfg, - // chaos.NewNetworkPartition, - // &chaos.Props{ - // FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, - // ToLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, - // DurationStr: "1m", - // }, - //}, - } - - for testCaseName, tc := range testCases { - testCase := tc - t.Run(fmt.Sprintf("OCR2VRF_%s", testCaseName), func(t *testing.T) { - t.Parallel() - testNetwork := networks.MustGetSelectedNetworkConfig(testConfig.Network)[0] // Need a new copy of the network for each test - testEnvironment := environment. - New(&environment.Config{ - NamespacePrefix: fmt.Sprintf( - "chaos-ocr2vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), - ), - Test: t, - }). - AddHelm(testCase.networkChart). - AddHelm(testCase.clChart) - err := testEnvironment.Run() - require.NoError(t, err, "Error running test environment") - if testEnvironment.WillUseRemoteRunner() { - return - } - - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 1, 2, ChaosGroupMinority) - require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 3, 5, ChaosGroupMajority) - require.NoError(t, err) - - testNetwork = seth_utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) - chainClient, err := seth_utils.GetChainClientWithConfigFunction(testConfig, testNetwork, seth_utils.OneEphemeralKeysLiveTestnetCheckFn) - require.NoError(t, err, "Error creating seth client") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) - require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") - - t.Cleanup(func() { - err := actions.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &testConfig) - require.NoError(t, err, "Error tearing down environment") - }) - - linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) - require.NoError(t, err, "Error deploying LINK token") - - mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) - require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") - - _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( - t, - linkToken, - mockETHLinkFeed, - chainClient, - nodeAddresses, - chainlinkNodes, - testNetwork, - ) - - //Request and Redeem Randomness to verify that process works fine - requestID := ocr2vrf_actions.RequestAndRedeemRandomness( - t, - consumerContract, - vrfBeaconContract, - ocr2vrf_constants.NumberOfRandomWordsToRequest, - subID, - ocr2vrf_constants.ConfirmationDelay, - ocr2vrf_constants.RandomnessRedeemTransmissionEventTimeout, - ) - - for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) - require.NoError(t, err) - l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") - require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") - } - - id, err := testEnvironment.Chaos.Run(testCase.chaosFunc(testEnvironment.Cfg.Namespace, testCase.chaosProps)) - require.NoError(t, err, "Error running Chaos Experiment") - l.Info().Msg("Chaos Applied") - - err = testEnvironment.Chaos.WaitForAllRecovered(id, time.Minute) - require.NoError(t, err, "Error waiting for Chaos Experiment to end") - l.Info().Msg("Chaos Recovered") - - //Request and Redeem Randomness again to see that after Chaos Experiment whole process is still working - requestID = ocr2vrf_actions.RequestAndRedeemRandomness( - t, - consumerContract, - vrfBeaconContract, - ocr2vrf_constants.NumberOfRandomWordsToRequest, - subID, - ocr2vrf_constants.ConfirmationDelay, - ocr2vrf_constants.RandomnessRedeemTransmissionEventTimeout, - ) - - for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) - require.NoError(t, err, "Error getting Randomness result from Consumer Contract") - l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") - require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") - } - }) - } -} diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 3b7eeac888c..54a02cf64f3 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -54,7 +54,7 @@ var ( func TestOCRChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Chaos", tc.OCR) + config, err := tc.GetConfig([]string{"Chaos"}, tc.OCR) require.NoError(t, err, "Error getting config") var overrideFn = func(_ interface{}, target interface{}) { diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index bf4dbd9df13..08a47101dc1 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -843,62 +843,6 @@ func (c *ChainlinkClient) ImportVRFKey(vrfExportKey *VRFExportKey) (*VRFKey, *ht return vrfKey, resp.RawResponse, err } -// MustCreateDkgSignKey creates a DKG Sign key on the Chainlink node -// and returns error if the request is unsuccessful -func (c *ChainlinkClient) MustCreateDkgSignKey() (*DKGSignKey, error) { - dkgSignKey := &DKGSignKey{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Sign Key") - resp, err := c.APIClient.R(). - SetResult(dkgSignKey). - Post("/v2/keys/dkgsign") - if err == nil { - err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) - } - return dkgSignKey, err -} - -// MustCreateDkgEncryptKey creates a DKG Encrypt key on the Chainlink node -// and returns error if the request is unsuccessful -func (c *ChainlinkClient) MustCreateDkgEncryptKey() (*DKGEncryptKey, error) { - dkgEncryptKey := &DKGEncryptKey{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Creating DKG Encrypt Key") - resp, err := c.APIClient.R(). - SetResult(dkgEncryptKey). - Post("/v2/keys/dkgencrypt") - if err == nil { - err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) - } - return dkgEncryptKey, err -} - -// MustReadDKGSignKeys reads all DKG Sign Keys from the Chainlink node returns err if response not 200 -func (c *ChainlinkClient) MustReadDKGSignKeys() (*DKGSignKeys, error) { - dkgSignKeys := &DKGSignKeys{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Sign Keys") - resp, err := c.APIClient.R(). - SetResult(dkgSignKeys). - Get("/v2/keys/dkgsign") - if err != nil { - return nil, err - } - err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) - return dkgSignKeys, err -} - -// MustReadDKGEncryptKeys reads all DKG Encrypt Keys from the Chainlink node returns err if response not 200 -func (c *ChainlinkClient) MustReadDKGEncryptKeys() (*DKGEncryptKeys, error) { - dkgEncryptKeys := &DKGEncryptKeys{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Reading DKG Encrypt Keys") - resp, err := c.APIClient.R(). - SetResult(dkgEncryptKeys). - Get("/v2/keys/dkgencrypt") - if err != nil { - return nil, err - } - err = VerifyStatusCode(resp.StatusCode(), http.StatusOK) - return dkgEncryptKeys, err -} - // CreateCSAKey creates a CSA key on the Chainlink node, only 1 CSA key per noe func (c *ChainlinkClient) CreateCSAKey() (*CSAKey, *http.Response, error) { csaKey := &CSAKey{} diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index 147238b7950..794e93f7276 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -10,6 +10,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" ) +const ( + CLNodeTestEmail = "notreal@fakeemail.ch" + CLNodeTestPassword = "fj293fbBnlQ!f9vNs" +) + type ChainlinkK8sClient struct { ChartName string PodName string @@ -74,8 +79,8 @@ func ConnectChainlinkNodes(e *environment.Environment) ([]*ChainlinkK8sClient, e for _, nodeDetails := range e.ChainlinkNodeDetails { c, err := NewChainlinkK8sClient(&ChainlinkConfig{ URL: nodeDetails.LocalIP, - Email: "notreal@fakeemail.ch", - Password: "fj293fbBnlQ!f9vNs", + Email: CLNodeTestEmail, + Password: CLNodeTestPassword, InternalIP: parseHostname(nodeDetails.InternalIP), }, nodeDetails.PodName, nodeDetails.ChartName) if err != nil { @@ -100,8 +105,8 @@ func ReconnectChainlinkNodes(testEnvironment *environment.Environment, nodes []* if details.ChartName == node.ChartName { // Make the link from client to pod consistent node, err = NewChainlinkK8sClient(&ChainlinkConfig{ URL: details.LocalIP, - Email: "notreal@fakeemail.ch", - Password: "fj293fbBnlQ!f9vNs", + Email: CLNodeTestEmail, + Password: CLNodeTestPassword, InternalIP: parseHostname(details.InternalIP), }, details.PodName, details.ChartName) if err != nil { @@ -136,8 +141,8 @@ func ConnectChainlinkNodeURLs(urls []string) ([]*ChainlinkK8sClient, error) { func ConnectChainlinkNodeURL(url string) (*ChainlinkK8sClient, error) { return NewChainlinkK8sClient(&ChainlinkConfig{ URL: url, - Email: "notreal@fakeemail.ch", - Password: "fj293fbBnlQ!f9vNs", + Email: CLNodeTestEmail, + Password: CLNodeTestPassword, InternalIP: parseHostname(url), }, parseHostname(url), // a decent guess diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index 586fd67f0e2..a0435d53368 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -214,50 +214,6 @@ type VRFKeys struct { Data []VRFKey `json:"data"` } -// DKGSignKeyAttributes is the model that represents the created DKG Sign key attributes when read -type DKGSignKeyAttributes struct { - PublicKey string `json:"publicKey"` -} - -// DKGSignKeyData is the model that represents the created DKG Sign key's data when read -type DKGSignKeyData struct { - Type string `json:"type"` - ID string `json:"id"` - Attributes DKGSignKeyAttributes `json:"attributes"` -} - -// DKGSignKey is the model that represents the created DKG Sign key when read -type DKGSignKey struct { - Data DKGSignKeyData `json:"data"` -} - -// DKGSignKeys is the model that represents the created DKGSignData key when read -type DKGSignKeys struct { - Data []DKGSignKey `json:"data"` -} - -// DKGEncryptKeyAttributes is the model that represents the created DKG Encrypt key attributes when read -type DKGEncryptKeyAttributes struct { - PublicKey string `json:"publicKey"` -} - -// DKGEncryptKeyData is the model that represents the created DKG Encrypt key's data when read -type DKGEncryptKeyData struct { - Type string `json:"type"` - ID string `json:"id"` - Attributes DKGEncryptKeyAttributes `json:"attributes"` -} - -// DKGEncryptKey is the model that represents the created DKG Encrypt key when read -type DKGEncryptKey struct { - Data DKGEncryptKeyData `json:"data"` -} - -// DKGEncryptKeys is the model that represents the created DKGEncryptKeys key when read -type DKGEncryptKeys struct { - Data []DKGEncryptKey `json:"data"` -} - // OCRKeys is the model that represents the created OCR keys when read type OCRKeys struct { Data []OCRKeyData `json:"data"` diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index c30eadd3d3d..45825a18ff3 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -21,8 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" ) type VRF interface { @@ -322,47 +320,6 @@ type VRFv2PlusWrapperLoadTestConsumer interface { GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) } -type DKG interface { - Address() string - AddClient(keyID string, clientAddress string) error - SetConfig( - signerAddresses []common.Address, - transmitterAddresses []common.Address, - f uint8, - onchainConfig []byte, - offchainConfigVersion uint64, - offchainConfig []byte, - ) error - WaitForConfigSetEvent(timeout time.Duration) (*dkg.DKGConfigSet, error) - WaitForTransmittedEvent(timeout time.Duration) (*dkg.DKGTransmitted, error) -} - -type VRFCoordinatorV3 interface { - Address() string - SetProducer(producerAddress string) error - CreateSubscription() error - FindSubscriptionID() (*big.Int, error) - AddConsumer(subId *big.Int, consumerAddress string) error - SetConfig(maxCallbackGasLimit, maxCallbackArgumentsLength uint32) error -} - -type VRFBeacon interface { - Address() string - SetPayees(transmitterAddresses []common.Address, payeesAddresses []common.Address) error - SetConfig( - signerAddresses []common.Address, - transmitterAddresses []common.Address, - f uint8, - onchainConfig []byte, - offchainConfigVersion uint64, - offchainConfig []byte, - ) error - WaitForConfigSetEvent(timeout time.Duration) (*vrf_beacon.VRFBeaconConfigSet, error) - WaitForNewTransmissionEvent(timeout time.Duration) (*vrf_beacon.VRFBeaconNewTransmission, error) - LatestConfigDigestAndEpoch(ctx context.Context) (vrf_beacon.LatestConfigDigestAndEpoch, - error) -} - type VRFBeaconConsumer interface { Address() string RequestRandomness( diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index ebe99da2d92..f2dc7e85ee7 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -99,11 +99,6 @@ func DefaultOffChainAggregatorOptions() OffchainOptions { // DefaultOffChainAggregatorConfig returns some base defaults for configuring an OCR contract func DefaultOffChainAggregatorConfig(numberNodes int) OffChainAggregatorConfig { - if numberNodes <= 4 { - log.Err(fmt.Errorf("insufficient number of nodes (%d) supplied for OCR, need at least 5", numberNodes)). - Int("Number Chainlink Nodes", numberNodes). - Msg("You likely need more chainlink nodes to properly configure OCR, try 5 or more.") - } s := []int{1} // First node's stage already inputted as a 1 in line above, so numberNodes-1. for i := 0; i < numberNodes-1; i++ { diff --git a/integration-tests/contracts/ethereum_contracts_automation.go b/integration-tests/contracts/ethereum_contracts_automation.go index c2c7576e0f0..bd0e1aafc82 100644 --- a/integration-tests/contracts/ethereum_contracts_automation.go +++ b/integration-tests/contracts/ethereum_contracts_automation.go @@ -1799,6 +1799,87 @@ func (v *EthereumKeeperRegistrar) Fund(_ *big.Float) error { panic("do not use this function, use actions.SendFunds instead") } +// register Upkeep with native token, only available from v2.3 +func (v *EthereumKeeperRegistrar) RegisterUpkeepFromKey(keyNum int, name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, wethTokenAddr string, isLogTrigger bool, isMercury bool) (*types.Transaction, error) { + if v.registrar23 == nil { + return nil, fmt.Errorf("RegisterUpkeepFromKey with native token is only supported in registrar version v2.3") + } + + registrarABI = cltypes.MustGetABI(registrar23.AutomationRegistrarABI) + txOpts := v.client.NewTXKeyOpts(keyNum, seth.WithValue(amount)) + + if isLogTrigger { + var topic0InBytes [32]byte + // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 + bytes0 := [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } + if isMercury { + // bytes representation of 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd + topic0InBytes = [32]byte{209, 255, 233, 228, 85, 129, 193, 29, 125, 159, 46, 213, 247, 82, 23, 205, 75, 233, 248, 183, 238, 230, 175, 15, 109, 3, 244, 109, 229, 57, 86, 205} + } else { + // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d + topic0InBytes = [32]byte{ + 61, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } + } + + logTriggerConfigStruct := acutils.IAutomationV21PlusCommonLogTriggerConfig{ + ContractAddress: common.HexToAddress(upkeepAddr), + FilterSelector: 0, + Topic0: topic0InBytes, + Topic1: bytes0, + Topic2: bytes0, + Topic3: bytes0, + } + encodedLogTriggerConfig, err := compatibleUtils.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) + if err != nil { + return nil, err + } + + params := registrar23.AutomationRegistrar23RegistrationParams{ + UpkeepContract: common.HexToAddress(upkeepAddr), + Amount: amount, + AdminAddress: common.HexToAddress(adminAddr), + GasLimit: gasLimit, + TriggerType: uint8(1), // trigger type + BillingToken: common.HexToAddress(wethTokenAddr), // native + Name: name, + EncryptedEmail: email, + CheckData: checkData, + TriggerConfig: encodedLogTriggerConfig, // log trigger upkeep + OffchainConfig: []byte{}, + } + + decodedTx, err := v.client.Decode(v.registrar23.RegisterUpkeep(txOpts, + params, + )) + return decodedTx.Transaction, err + } + + params := registrar23.AutomationRegistrar23RegistrationParams{ + UpkeepContract: common.HexToAddress(upkeepAddr), + Amount: amount, + AdminAddress: common.HexToAddress(adminAddr), + GasLimit: gasLimit, + TriggerType: uint8(0), // trigger type + BillingToken: common.HexToAddress(wethTokenAddr), // native + Name: name, + EncryptedEmail: email, + CheckData: checkData, + TriggerConfig: []byte{}, // conditional upkeep + OffchainConfig: []byte{}, + } + + decodedTx, err := v.client.Decode(v.registrar23.RegisterUpkeep(txOpts, + params, + )) + return decodedTx.Transaction, err +} + // EncodeRegisterRequest encodes register request to call it through link token TransferAndCall func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool, isMercury bool, linkTokenAddr string) ([]byte, error) { if v.registrar20 != nil { @@ -2056,9 +2137,11 @@ func DeployKeeperRegistrar(client *seth.Client, registryVersion eth_contracts.Ke billingTokens := []common.Address{ common.HexToAddress(linkAddr), + common.HexToAddress(registrarSettings.WETHTokenAddr), } minRegistrationFees := []*big.Int{ big.NewInt(10), + big.NewInt(10), } data, err := client.DeployContract(client.NewTXOpts(), "KeeperRegistrar2_3", *abi, common.FromHex(registrar23.AutomationRegistrarMetaData.Bin), diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index 84543627d49..34c78b3fc60 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -27,6 +27,8 @@ type KeeperRegistrar interface { EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool, isMercury bool, linkTokenAddr string) ([]byte, error) Fund(ethAmount *big.Float) error + + RegisterUpkeepFromKey(keyNum int, name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, wethTokenAddr string, isLogTrigger bool, isMercury bool) (*types.Transaction, error) } type UpkeepTranscoder interface { diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go deleted file mode 100644 index 4ef0740fdbc..00000000000 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ /dev/null @@ -1,523 +0,0 @@ -package contracts - -import ( - "context" - "encoding/hex" - "fmt" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/seth" - - "github.com/smartcontractkit/chainlink/integration-tests/wrappers" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" -) - -// EthereumDKG represents DKG contract -type EthereumDKG struct { - address common.Address - client *seth.Client - dkg *dkg.DKG -} - -// EthereumVRFCoordinatorV3 represents VRFCoordinatorV3 contract -type EthereumVRFCoordinatorV3 struct { - address common.Address - client *seth.Client - vrfCoordinatorV3 *vrf_coordinator.VRFCoordinator -} - -// EthereumVRFBeacon represents VRFBeacon contract -type EthereumVRFBeacon struct { - address common.Address - client *seth.Client - vrfBeacon *vrf_beacon.VRFBeacon -} - -// EthereumVRFBeaconConsumer represents VRFBeaconConsumer contract -type EthereumVRFBeaconConsumer struct { - address common.Address - client *seth.Client - vrfBeaconConsumer *vrf_beacon_consumer.BeaconVRFConsumer -} - -// DeployDKG deploys DKG contract -func DeployDKG(seth *seth.Client) (DKG, error) { - abi, err := dkg.DKGMetaData.GetAbi() - if err != nil { - return &EthereumDKG{}, fmt.Errorf("failed to get DKG ABI: %w", err) - } - - data, err := seth.DeployContract( - seth.NewTXOpts(), - "DKG", - *abi, - common.FromHex(dkg.DKGMetaData.Bin)) - if err != nil { - return &EthereumDKG{}, fmt.Errorf("DKG instance deployment have failed: %w", err) - } - - contract, err := dkg.NewDKG(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumDKG{}, fmt.Errorf("failed to instantiate DKG instance: %w", err) - } - - return &EthereumDKG{ - client: seth, - dkg: contract, - address: data.Address, - }, err -} - -// DeployOCR2VRFCoordinator deploys CR2VRFCoordinator contract -func DeployOCR2VRFCoordinator(seth *seth.Client, beaconPeriodBlocksCount *big.Int, linkAddress string) (VRFCoordinatorV3, error) { - abi, err := vrf_coordinator.VRFCoordinatorMetaData.GetAbi() - if err != nil { - return &EthereumVRFCoordinatorV3{}, fmt.Errorf("failed to get VRFCoordinatorV3 ABI: %w", err) - } - - data, err := seth.DeployContract( - seth.NewTXOpts(), - "VRFCoordinatorV3", - *abi, - common.FromHex(vrf_coordinator.VRFCoordinatorMetaData.Bin), - beaconPeriodBlocksCount, common.HexToAddress(linkAddress)) - if err != nil { - return &EthereumVRFCoordinatorV3{}, fmt.Errorf("VRFCoordinatorV3 instance deployment have failed: %w", err) - } - - contract, err := vrf_coordinator.NewVRFCoordinator(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRFCoordinatorV3{}, fmt.Errorf("failed to instantiate VRFCoordinatorV3 instance: %w", err) - } - - return &EthereumVRFCoordinatorV3{ - client: seth, - vrfCoordinatorV3: contract, - address: data.Address, - }, err -} - -// DeployVRFBeacon deploys DeployVRFBeacon contract -func DeployVRFBeacon(seth *seth.Client, vrfCoordinatorAddress string, linkAddress string, dkgAddress string, keyId string) (VRFBeacon, error) { - abi, err := vrf_beacon.VRFBeaconMetaData.GetAbi() - if err != nil { - return &EthereumVRFBeacon{}, fmt.Errorf("failed to get VRFBeacon ABI: %w", err) - } - keyIDBytes, err := DecodeHexTo32ByteArray(keyId) - if err != nil { - return nil, err - } - data, err := seth.DeployContract( - seth.NewTXOpts(), - "VRFBeacon", - *abi, - common.FromHex(vrf_beacon.VRFBeaconMetaData.Bin), - common.HexToAddress(linkAddress), common.HexToAddress(vrfCoordinatorAddress), common.HexToAddress(dkgAddress), keyIDBytes) - if err != nil { - return &EthereumVRFBeacon{}, fmt.Errorf("VRFBeacon instance deployment have failed: %w", err) - } - - contract, err := vrf_beacon.NewVRFBeacon(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRFBeacon{}, fmt.Errorf("failed to instantiate VRFBeacon instance: %w", err) - } - - return &EthereumVRFBeacon{ - client: seth, - vrfBeacon: contract, - address: data.Address, - }, err -} - -// DeployBatchBlockhashStore deploys DeployBatchBlockhashStore contract -func DeployBatchBlockhashStore(seth *seth.Client, blockhashStoreAddr string) (BatchBlockhashStore, error) { - abi, err := batch_blockhash_store.BatchBlockhashStoreMetaData.GetAbi() - if err != nil { - return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to get BatchBlockhashStore ABI: %w", err) - } - data, err := seth.DeployContract( - seth.NewTXOpts(), - "BatchBlockhashStore", - *abi, - common.FromHex(batch_blockhash_store.BatchBlockhashStoreMetaData.Bin), - common.HexToAddress(blockhashStoreAddr)) - if err != nil { - return &EthereumBatchBlockhashStore{}, fmt.Errorf("BatchBlockhashStore instance deployment have failed: %w", err) - } - - contract, err := batch_blockhash_store.NewBatchBlockhashStore(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to instantiate BatchBlockhashStore instance: %w", err) - } - - return &EthereumBatchBlockhashStore{ - client: seth, - batchBlockhashStore: contract, - address: data.Address, - }, err -} - -// todo - solve import cycle -func DecodeHexTo32ByteArray(val string) ([32]byte, error) { - var byteArray [32]byte - decoded, err := hex.DecodeString(val) - if err != nil { - return [32]byte{}, err - } - if len(decoded) != 32 { - return [32]byte{}, fmt.Errorf("expected value to be 32 bytes but received %d bytes", len(decoded)) - } - copy(byteArray[:], decoded) - return byteArray, err -} - -// DeployVRFBeaconConsumer deploys VRFv@ consumer contract -func DeployVRFBeaconConsumer(seth *seth.Client, vrfCoordinatorAddress string, beaconPeriodBlockCount *big.Int) (VRFBeaconConsumer, error) { - abi, err := vrf_beacon_consumer.BeaconVRFConsumerMetaData.GetAbi() - if err != nil { - return &EthereumVRFBeaconConsumer{}, fmt.Errorf("failed to get VRFBeaconConsumer ABI: %w", err) - } - data, err := seth.DeployContract( - seth.NewTXOpts(), - "VRFBeaconConsumer", - *abi, - common.FromHex(vrf_beacon_consumer.BeaconVRFConsumerMetaData.Bin), - common.HexToAddress(vrfCoordinatorAddress), false, beaconPeriodBlockCount) - if err != nil { - return &EthereumVRFBeaconConsumer{}, fmt.Errorf("VRFBeaconConsumer instance deployment have failed: %w", err) - } - - contract, err := vrf_beacon_consumer.NewBeaconVRFConsumer(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) - if err != nil { - return &EthereumVRFBeaconConsumer{}, fmt.Errorf("failed to instantiate VRFBeaconConsumer instance: %w", err) - } - - return &EthereumVRFBeaconConsumer{ - client: seth, - vrfBeaconConsumer: contract, - address: data.Address, - }, err -} - -func (dkgContract *EthereumDKG) Address() string { - return dkgContract.address.Hex() -} - -func (dkgContract *EthereumDKG) AddClient(keyID string, clientAddress string) error { - keyIDBytes, err := DecodeHexTo32ByteArray(keyID) - if err != nil { - return err - } - _, err = dkgContract.client.Decode(dkgContract.dkg.AddClient( - dkgContract.client.NewTXOpts(), - keyIDBytes, - common.HexToAddress(clientAddress), - )) - return err -} - -func (dkgContract *EthereumDKG) SetConfig( - signerAddresses []common.Address, - transmitterAddresses []common.Address, - f uint8, - onchainConfig []byte, - offchainConfigVersion uint64, - offchainConfig []byte, -) error { - _, err := dkgContract.client.Decode(dkgContract.dkg.SetConfig( - dkgContract.client.NewTXOpts(), - signerAddresses, - transmitterAddresses, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig, - )) - return err -} - -func (dkgContract *EthereumDKG) WaitForTransmittedEvent(timeout time.Duration) (*dkg.DKGTransmitted, error) { - transmittedEventsChannel := make(chan *dkg.DKGTransmitted) - subscription, err := dkgContract.dkg.WatchTransmitted(nil, transmittedEventsChannel) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err = <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for DKGTransmitted event") - case transmittedEvent := <-transmittedEventsChannel: - return transmittedEvent, nil - } - } -} - -func (dkgContract *EthereumDKG) WaitForConfigSetEvent(timeout time.Duration) (*dkg.DKGConfigSet, error) { - configSetEventsChannel := make(chan *dkg.DKGConfigSet) - subscription, err := dkgContract.dkg.WatchConfigSet(nil, configSetEventsChannel) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err = <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for DKGConfigSet event") - case configSetEvent := <-configSetEventsChannel: - return configSetEvent, nil - } - } -} - -func (coordinator *EthereumVRFCoordinatorV3) Address() string { - return coordinator.address.Hex() -} - -func (coordinator *EthereumVRFCoordinatorV3) SetProducer(producerAddress string) error { - _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.SetProducer( - coordinator.client.NewTXOpts(), - common.HexToAddress(producerAddress), - )) - return err -} - -func (coordinator *EthereumVRFCoordinatorV3) CreateSubscription() error { - _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.CreateSubscription( - coordinator.client.NewTXOpts(), - )) - return err -} - -func (coordinator *EthereumVRFCoordinatorV3) FindSubscriptionID() (*big.Int, error) { - fopts := &bind.FilterOpts{} - owner := coordinator.client.MustGetRootKeyAddress() - - subscriptionIterator, err := coordinator.vrfCoordinatorV3.FilterSubscriptionCreated( - fopts, - nil, - []common.Address{owner}, - ) - if err != nil { - return nil, err - } - - if !subscriptionIterator.Next() { - return nil, fmt.Errorf("expected at least 1 subID for the given owner %s", owner) - } - - return subscriptionIterator.Event.SubId, nil -} - -func (coordinator *EthereumVRFCoordinatorV3) AddConsumer(subId *big.Int, consumerAddress string) error { - _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.AddConsumer( - coordinator.client.NewTXOpts(), - subId, - common.HexToAddress(consumerAddress), - )) - return err -} - -func (coordinator *EthereumVRFCoordinatorV3) SetConfig(maxCallbackGasLimit uint32, maxCallbackArgumentsLength uint32) error { - _, err := coordinator.client.Decode(coordinator.vrfCoordinatorV3.SetCallbackConfig( - coordinator.client.NewTXOpts(), - vrf_coordinator.VRFCoordinatorCallbackConfig{ - MaxCallbackGasLimit: maxCallbackGasLimit, - MaxCallbackArgumentsLength: maxCallbackArgumentsLength, // 5 EVM words - }, - )) - return err -} - -func (beacon *EthereumVRFBeacon) Address() string { - return beacon.address.Hex() -} - -func (beacon *EthereumVRFBeacon) SetPayees(transmitterAddresses []common.Address, payeesAddresses []common.Address) error { - _, err := beacon.client.Decode(beacon.vrfBeacon.SetPayees( - beacon.client.NewTXOpts(), - transmitterAddresses, - payeesAddresses, - )) - return err -} - -func (beacon *EthereumVRFBeacon) SetConfig( - signerAddresses []common.Address, - transmitterAddresses []common.Address, - f uint8, - onchainConfig []byte, - offchainConfigVersion uint64, - offchainConfig []byte, -) error { - _, err := beacon.client.Decode(beacon.vrfBeacon.SetConfig( - beacon.client.NewTXOpts(), - signerAddresses, - transmitterAddresses, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig, - )) - return err -} - -func (beacon *EthereumVRFBeacon) WaitForConfigSetEvent(timeout time.Duration) (*vrf_beacon.VRFBeaconConfigSet, error) { - configSetEventsChannel := make(chan *vrf_beacon.VRFBeaconConfigSet) - subscription, err := beacon.vrfBeacon.WatchConfigSet(nil, configSetEventsChannel) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for config set event") - case configSetEvent := <-configSetEventsChannel: - return configSetEvent, nil - } - } -} - -func (beacon *EthereumVRFBeacon) WaitForNewTransmissionEvent(timeout time.Duration) (*vrf_beacon.VRFBeaconNewTransmission, error) { - newTransmissionEventsChannel := make(chan *vrf_beacon.VRFBeaconNewTransmission) - subscription, err := beacon.vrfBeacon.WatchNewTransmission(nil, newTransmissionEventsChannel, nil) - if err != nil { - return nil, err - } - defer subscription.Unsubscribe() - - for { - select { - case err := <-subscription.Err(): - return nil, err - case <-time.After(timeout): - return nil, fmt.Errorf("timeout waiting for new transmission event") - case newTransmissionEvent := <-newTransmissionEventsChannel: - return newTransmissionEvent, nil - } - } -} - -func (beacon *EthereumVRFBeacon) LatestConfigDigestAndEpoch(ctx context.Context) (vrf_beacon.LatestConfigDigestAndEpoch, - error) { - opts := &bind.CallOpts{ - From: beacon.client.MustGetRootKeyAddress(), - Context: ctx, - } - return beacon.vrfBeacon.LatestConfigDigestAndEpoch(opts) -} - -func (consumer *EthereumVRFBeaconConsumer) Address() string { - return consumer.address.Hex() -} - -func (consumer *EthereumVRFBeaconConsumer) RequestRandomness( - numWords uint16, - subID, confirmationDelayArg *big.Int, -) (*types.Receipt, error) { - tx, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRequestRandomness( - consumer.client.NewTXOpts(), - numWords, - subID, - confirmationDelayArg, - )) - if err != nil { - return nil, fmt.Errorf("TestRequestRandomness failed, err: %w", err) - } - log.Info().Interface("Sub ID", subID). - Interface("Number of Words", numWords). - Interface("Number of Confirmations", confirmationDelayArg). - Msg("RequestRandomness called") - return tx.Receipt, nil -} - -func (consumer *EthereumVRFBeaconConsumer) RedeemRandomness( - subID, requestID *big.Int, -) error { - _, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRedeemRandomness( - consumer.client.NewTXOpts(), - subID, - requestID, - )) - if err != nil { - return err - } - log.Info().Interface("Sub ID", subID). - Interface("Request ID", requestID). - Msg("RedeemRandomness called") - return nil -} - -func (consumer *EthereumVRFBeaconConsumer) RequestRandomnessFulfillment( - numWords uint16, - subID, confirmationDelayArg *big.Int, - requestGasLimit uint32, - callbackGasLimit uint32, - arguments []byte, -) (*types.Receipt, error) { - opts := consumer.client.NewTXOpts() - // overriding gas limit because gas estimated by TestRequestRandomnessFulfillment - // is incorrect - opts.GasLimit = uint64(requestGasLimit) - tx, err := consumer.client.Decode(consumer.vrfBeaconConsumer.TestRequestRandomnessFulfillment( - opts, - subID, - numWords, - confirmationDelayArg, - callbackGasLimit, - arguments, - )) - if err != nil { - return nil, fmt.Errorf("TestRequestRandomnessFulfillment failed, err: %w", err) - } - log.Info().Interface("Sub ID", subID). - Interface("Number of Words", numWords). - Interface("Number of Confirmations", confirmationDelayArg). - Interface("Callback Gas Limit", callbackGasLimit). - Msg("RequestRandomnessFulfillment called") - return tx.Receipt, nil -} - -func (consumer *EthereumVRFBeaconConsumer) IBeaconPeriodBlocks(ctx context.Context) (*big.Int, error) { - opts := &bind.CallOpts{ - From: consumer.client.MustGetRootKeyAddress(), - Context: ctx, - } - return consumer.vrfBeaconConsumer.IBeaconPeriodBlocks(opts) -} - -func (consumer *EthereumVRFBeaconConsumer) GetRequestIdsBy(ctx context.Context, nextBeaconOutputHeight *big.Int, confDelay *big.Int) (*big.Int, error) { - opts := &bind.CallOpts{ - From: consumer.client.MustGetRootKeyAddress(), - Context: ctx, - } - return consumer.vrfBeaconConsumer.SRequestsIDs(opts, nextBeaconOutputHeight, confDelay) -} - -func (consumer *EthereumVRFBeaconConsumer) GetRandomnessByRequestId(ctx context.Context, requestID *big.Int, numWordIndex *big.Int) (*big.Int, error) { - opts := &bind.CallOpts{ - From: consumer.client.MustGetRootKeyAddress(), - Context: ctx, - } - return consumer.vrfBeaconConsumer.SReceivedRandomnessByRequestID(opts, requestID, numWordIndex) -} diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 9f6f6665d21..ea0ee18e937 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/seth" "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" @@ -729,6 +730,34 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte }, nil } +// DeployBatchBlockhashStore deploys DeployBatchBlockhashStore contract +func DeployBatchBlockhashStore(seth *seth.Client, blockhashStoreAddr string) (BatchBlockhashStore, error) { + abi, err := batch_blockhash_store.BatchBlockhashStoreMetaData.GetAbi() + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to get BatchBlockhashStore ABI: %w", err) + } + data, err := seth.DeployContract( + seth.NewTXOpts(), + "BatchBlockhashStore", + *abi, + common.FromHex(batch_blockhash_store.BatchBlockhashStoreMetaData.Bin), + common.HexToAddress(blockhashStoreAddr)) + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("BatchBlockhashStore instance deployment have failed: %w", err) + } + + contract, err := batch_blockhash_store.NewBatchBlockhashStore(data.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBatchBlockhashStore{}, fmt.Errorf("failed to instantiate BatchBlockhashStore instance: %w", err) + } + + return &EthereumBatchBlockhashStore{ + client: seth, + batchBlockhashStore: contract, + address: data.Address, + }, err +} + func DeployVRFCoordinatorV2PlusUpgradedVersion(client *seth.Client, bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) { abi, err := vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionMetaData.GetAbi() if err != nil { diff --git a/integration-tests/crib/connect.go b/integration-tests/crib/connect.go new file mode 100644 index 00000000000..446c53d8f38 --- /dev/null +++ b/integration-tests/crib/connect.go @@ -0,0 +1,120 @@ +package crib + +import ( + "fmt" + "os" + "time" + + "github.com/pkg/errors" + "github.com/smartcontractkit/seth" + + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + msClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/client" +) + +const ( + // these are constants for simulated CRIB that should never change + // CRIB: https://github.com/smartcontractkit/crib/tree/main/core + // Core Chart: https://github.com/smartcontractkit/infra-charts/tree/main/chainlink-cluster + mockserverCRIBTemplate = "https://%s-mockserver%s" + internalNodeDNSTemplate = "app-node%d" + ingressNetworkWSURLTemplate = "wss://%s-geth-1337-ws%s" + ingressNetworkHTTPURLTemplate = "https://%s-geth-1337-http%s" +) + +func setSethConfig(cfg tc.TestConfig, netWSURL string, netHTTPURL string) { + netName := "CRIB_SIMULATED" + cfg.Network.SelectedNetworks = []string{netName} + cfg.Network.RpcHttpUrls = map[string][]string{} + cfg.Network.RpcHttpUrls[netName] = []string{netHTTPURL} + cfg.Network.RpcWsUrls = map[string][]string{} + cfg.Network.RpcWsUrls[netName] = []string{netWSURL} + cfg.Seth.EphemeralAddrs = ptr.Ptr(int64(0)) +} + +// ConnectRemote connects to a local environment, see https://github.com/smartcontractkit/crib/tree/main/core +// connects to default CRIB network if simulated = true +func ConnectRemote(simulated bool) ( + *seth.Client, + *msClient.MockserverClient, + *client.ChainlinkK8sClient, + []*client.ChainlinkK8sClient, + error, +) { + ingressSuffix := os.Getenv("K8S_STAGING_INGRESS_SUFFIX") + if ingressSuffix == "" { + return nil, nil, nil, nil, errors.New("K8S_STAGING_INGRESS_SUFFIX must be set to connect to k8s ingresses") + } + config, err := tc.GetConfig([]string{"CRIB"}, tc.OCR) + if err != nil { + return nil, nil, nil, nil, err + } + if config.CRIB.CLNodesNum < 2 { + return nil, nil, nil, nil, fmt.Errorf("not enough chainlink nodes, need at least 2, TOML key: [CRIB.nodes]") + } + cfg := config.CRIB + mockserverURL := fmt.Sprintf(mockserverCRIBTemplate, cfg.Namespace, ingressSuffix) + var sethClient *seth.Client + if simulated { + netWSURL := fmt.Sprintf(ingressNetworkWSURLTemplate, cfg.Namespace, ingressSuffix) + netHTTPURL := fmt.Sprintf(ingressNetworkHTTPURLTemplate, cfg.Namespace, ingressSuffix) + setSethConfig(config, netWSURL, netHTTPURL) + net := blockchain.EVMNetwork{ + Name: cfg.NetworkName, + Simulated: true, + SupportsEIP1559: true, + ClientImplementation: blockchain.EthereumClientImplementation, + ChainID: 1337, + PrivateKeys: []string{ + "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + }, + URLs: []string{netWSURL}, + HTTPURLs: []string{netHTTPURL}, + ChainlinkTransactionLimit: 500000, + Timeout: blockchain.StrDuration{Duration: 2 * time.Minute}, + MinimumConfirmations: 1, + GasEstimationBuffer: 10000, + } + sethClient, err = seth_utils.GetChainClient(config, net) + if err != nil { + return nil, nil, nil, nil, err + } + } + // bootstrap node + clClients := make([]*client.ChainlinkK8sClient, 0) + c, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{ + URL: fmt.Sprintf("https://%s-node%d%s", cfg.Namespace, 1, ingressSuffix), + Email: client.CLNodeTestEmail, + InternalIP: fmt.Sprintf(internalNodeDNSTemplate, 1), + Password: client.CLNodeTestPassword, + }, fmt.Sprintf(internalNodeDNSTemplate, 1), cfg.Namespace) + if err != nil { + return nil, nil, nil, nil, err + } + clClients = append(clClients, c) + // all the other nodes, indices of nodes in CRIB starts with 1 + for i := 2; i <= cfg.CLNodesNum; i++ { + cl, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{ + URL: fmt.Sprintf("https://%s-node%d%s", cfg.Namespace, i, ingressSuffix), + Email: client.CLNodeTestEmail, + InternalIP: fmt.Sprintf(internalNodeDNSTemplate, i), + Password: client.CLNodeTestPassword, + }, fmt.Sprintf(internalNodeDNSTemplate, i), cfg.Namespace) + if err != nil { + return nil, nil, nil, nil, err + } + clClients = append(clClients, cl) + } + mockServerClient := msClient.NewMockserverClient(&msClient.MockserverConfig{ + LocalURL: mockserverURL, + ClusterURL: mockserverURL, + }) + + //nolint:gosec // G602 - false positive https://github.com/securego/gosec/issues/1005 + return sethClient, mockServerClient, clClients[0], clClients[1:], nil +} diff --git a/integration-tests/docker/cmd/internal/commands.go b/integration-tests/docker/cmd/internal/commands.go index e05e5d89fac..9939765f7f8 100644 --- a/integration-tests/docker/cmd/internal/commands.go +++ b/integration-tests/docker/cmd/internal/commands.go @@ -28,7 +28,7 @@ var StartNodesCmd = &cobra.Command{ log.Logger = logging.GetLogger(nil, "CORE_DOCKER_ENV_LOG_LEVEL") log.Info().Msg("Starting docker test env with Chainlink nodes..") - config, err := testconfig.GetConfig("Smoke", testconfig.OCR2) + config, err := testconfig.GetConfig([]string{"Smoke"}, testconfig.OCR2) if err != nil { return err } diff --git a/integration-tests/experiments/gas_test.go b/integration-tests/experiments/gas_test.go index 88bfbcf1926..4d1f4597111 100644 --- a/integration-tests/experiments/gas_test.go +++ b/integration-tests/experiments/gas_test.go @@ -18,7 +18,7 @@ import ( func TestGasExperiment(t *testing.T) { l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Soak", tc.OCR) + config, err := tc.GetConfig([]string{"Soak"}, tc.OCR) require.NoError(t, err, "Error getting config") network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 91b9a5821be..ff2cb34e842 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -28,13 +28,12 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf - github.com/smartcontractkit/chainlink-testing-framework v1.31.4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe + github.com/smartcontractkit/chainlink-testing-framework v1.31.7 github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 - github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37 - github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e github.com/smartcontractkit/seth v1.0.12 github.com/smartcontractkit/wasp v0.4.7 github.com/spf13/cobra v1.8.0 @@ -42,7 +41,6 @@ require ( github.com/test-go/testify v1.1.4 github.com/testcontainers/testcontainers-go v0.28.0 github.com/umbracle/ethgo v0.1.3 - go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/zap v1.26.0 golang.org/x/sync v0.6.0 golang.org/x/text v0.14.0 @@ -386,14 +384,14 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d // indirect - github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.8.1 // indirect + github.com/smartcontractkit/wsrpc v0.7.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/afero v1.9.5 // indirect @@ -433,6 +431,7 @@ require ( github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect + go.dedis.ch/kyber/v3 v3.1.0 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 3c423d9d7ea..c5dd6af880a 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -819,6 +819,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1512,32 +1513,30 @@ 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.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf h1:d9AS/K8RSVG64USb20N/U7RaPOsYPcmuLGJq7iE+caM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf/go.mod h1:L32xvCpk84Nglit64OhySPMP1tM3TTBK7Tw0qZl7Sd4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d h1:5tgMC5Gi2UAOKZ+m28W8ubjLeR0pQCAcrz6eQ0rW510= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe h1:lYyWmjheglMu0y3JmfSqs9Dm4tZO34RmbUTOtQ4CadE= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe/go.mod h1:EWvSuqIJUYXZLEHewC7WCaPylM2jyjF3Q36BZPS4MoI= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 h1:TMOoYaeSDkkI3jkCH7lKHOZaLkeDuxFTNC+XblD6M0M= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 h1:Vs6myS+bpPwb8chUY7XxveJyhvejknhOmhDTddgsK5I= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527/go.mod h1:KRK7KlAEpmORi+nJgT0vxQVWvlLEBQ6zgzXziZuKvUM= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h1:MD80ZRCTvxxJ8PBmhtrKoTnky8cVNYrCrIBLVRbrOM0= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 h1:YudTCEe/2xWdfPY/ESSiPFW4MVsrAoi2MWPwRUJ6QAA= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 h1:640M3TP06nBckEVqRZljcG/7AJlBxJ6vLXTHy6xCtwE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba h1:YNSlhK5mobyAaw02LPGgIEuS3lXyCTXcc6oaV2L6uUI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU= -github.com/smartcontractkit/chainlink-testing-framework v1.31.4 h1:5/zF5Z2w+/HTvUSSJNhWSiHvlQ2O2qxRw4e1fBbVraQ= -github.com/smartcontractkit/chainlink-testing-framework v1.31.4/go.mod h1:E6uNEZhZZid9PHv6/Kq5Vn63GlO61ZcKB+/f0DKo3Q4= +github.com/smartcontractkit/chainlink-testing-framework v1.31.7 h1:Vy4ah8VAfj+Y7vVmhjvwyAO6wG+Fp2vzdkSJwJPMQO4= +github.com/smartcontractkit/chainlink-testing-framework v1.31.7/go.mod h1:E6uNEZhZZid9PHv6/Kq5Vn63GlO61ZcKB+/f0DKo3Q4= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 h1:Kk5OVlx/5g9q3Z3lhxytZS4/f8ds1MiNM8yaHgK3Oe8= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU= -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= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37 h1:ZEhn2Yo1jY4hqy8nasDL4k4pNtopT3rS3Ap1GDb7ODc= github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37/go.mod h1:/kFr0D7SI/vueXl1N03uzOun4nViGPFRyA5X6eL3jXw= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e h1:9ypZ/8aW8Vm497i1gXHcT96oNLiu88jbg9QdX+IUE3E= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/seth v1.0.12 h1:iVdgMx42XWanPPnBaM5StR4c1XsTr/0/B/kKRZL5BsY= github.com/smartcontractkit/seth v1.0.12/go.mod h1:thWtbLyW4nRHJGzC5heknQDORoJPErE15sF34LHkorg= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= @@ -1546,8 +1545,8 @@ github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:D github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wasp v0.4.7 h1:7mKJfwzFbuE8xVLUYtLt7Bjw8q/bmVZRW6Ks8kc1LVM= github.com/smartcontractkit/wasp v0.4.7/go.mod h1:jeabvyXikb2aNoLQwcZGqaz17efrR8NJhpq4seAmdgs= -github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= -github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= +github.com/smartcontractkit/wsrpc v0.7.3 h1:CKYZfawZShZGfvsQep1F9oBansnFk9ByZPCdTMpLphw= +github.com/smartcontractkit/wsrpc v0.7.3/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1729,7 +1728,6 @@ go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0= go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= -go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= @@ -1814,6 +1812,7 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= diff --git a/integration-tests/k8s/connect.go b/integration-tests/k8s/connect.go deleted file mode 100644 index be1f9a25f9d..00000000000 --- a/integration-tests/k8s/connect.go +++ /dev/null @@ -1,99 +0,0 @@ -package k8s - -import ( - "fmt" - "os" - "time" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - client2 "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink/integration-tests/client" -) - -const ( - DefaultConfigFilePath = "../connect.toml" - ErrReadConnectionConfig = "failed to read TOML environment connection config" - ErrUnmarshalConnectionConfig = "failed to unmarshal TOML environment connection config" -) - -type ConnectionVars struct { - Namespace string `toml:"namespace"` - NetworkName string `toml:"network_name"` - NetworkChainID int64 `toml:"network_chain_id"` - NetworkPrivateKey string `toml:"network_private_key"` - NetworkWSURL string `toml:"network_ws_url"` - NetworkHTTPURL string `toml:"network_http_url"` - CLNodesNum int `toml:"cl_nodes_num"` - CLNodeURLTemplate string `toml:"cl_node_url_template"` - CLNodeInternalDNSRecordTemplate string `toml:"cl_node_internal_dns_record_template"` - CLNodeUser string `toml:"cl_node_user"` - CLNodePassword string `toml:"cl_node_password"` - MockServerURL string `toml:"mockserver_url"` -} - -// ConnectRemote connects to a local environment, see charts/chainlink-cluster -func ConnectRemote() (*blockchain.EVMNetwork, *client2.MockserverClient, *client.ChainlinkK8sClient, []*client.ChainlinkK8sClient, error) { - cfg, err := ReadConfig() - if err != nil { - return &blockchain.EVMNetwork{}, nil, nil, nil, err - } - net := &blockchain.EVMNetwork{ - Name: cfg.NetworkName, - Simulated: true, - SupportsEIP1559: true, - ClientImplementation: blockchain.EthereumClientImplementation, - ChainID: 1337, - PrivateKeys: []string{ - cfg.NetworkPrivateKey, - }, - URLs: []string{cfg.NetworkWSURL}, - HTTPURLs: []string{cfg.NetworkHTTPURL}, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.StrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } - clClients := make([]*client.ChainlinkK8sClient, 0) - for i := 1; i <= cfg.CLNodesNum; i++ { - c, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{ - URL: fmt.Sprintf(cfg.CLNodeURLTemplate, i), - Email: cfg.CLNodeUser, - InternalIP: fmt.Sprintf(cfg.CLNodeInternalDNSRecordTemplate, i), - Password: cfg.CLNodePassword, - }, fmt.Sprintf(cfg.CLNodeInternalDNSRecordTemplate, i), cfg.Namespace) - if err != nil { - return &blockchain.EVMNetwork{}, nil, nil, nil, err - } - clClients = append(clClients, c) - } - msClient := client2.NewMockserverClient(&client2.MockserverConfig{ - LocalURL: cfg.MockServerURL, - ClusterURL: cfg.MockServerURL, - }) - - if len(clClients) < 2 { - return &blockchain.EVMNetwork{}, nil, nil, nil, fmt.Errorf("not enough chainlink nodes, need at least 2, got %d", len(clClients)) - } - - //nolint:gosec // G602 - how is this potentially causing slice out of bounds is beyond me - return net, msClient, clClients[0], clClients[1:], nil -} - -func ReadConfig() (*ConnectionVars, error) { - var cfg *ConnectionVars - var d []byte - var err error - d, err = os.ReadFile(DefaultConfigFilePath) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadConnectionConfig, err) - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalConnectionConfig, err) - } - log.Info().Interface("Config", cfg).Msg("Connecting to environment from config") - return cfg, nil -} diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index c1b6a6d4a87..b0555cdd3f8 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -89,8 +89,9 @@ Password = '%s'` "memory": "4Gi", }, }, - "stateful": true, - "capacity": "20Gi", + "stateful": true, + "capacity": "20Gi", + "enablePrometheusPostgresExporter": true, } recNodeSpec = map[string]interface{}{ @@ -153,7 +154,7 @@ func TestLogTrigger(t *testing.T) { ctx := tests.Context(t) l := logging.GetTestLogger(t) - loadedTestConfig, err := tc.GetConfig("Load", tc.Automation) + loadedTestConfig, err := tc.GetConfig([]string{"Load"}, tc.Automation) if err != nil { t.Fatal(err) } diff --git a/integration-tests/load/connect.toml b/integration-tests/load/connect.toml deleted file mode 100644 index 919c5102c84..00000000000 --- a/integration-tests/load/connect.toml +++ /dev/null @@ -1,13 +0,0 @@ -# this is a static configuration to connect with CRIB k8s environment (Default Geth) -namespace = "cl-cluster" -network_name = "geth" -network_chain_id = 1337 -network_private_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" -network_ws_url = "ws://geth-1337:8546" -network_http_url = "http://geth:8544" -cl_nodes_num = 6 -cl_node_url_template = "http://app-node-%d:6688" -cl_node_internal_dns_record_template = "app-node-%d" -cl_node_user = "notreal@fakeemail.ch" -cl_node_password = "fj293fbBnlQ!f9vNs" -mockserver_url = "http://mockserver:1080" \ No newline at end of file diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index 49102bcaa66..374b3df705c 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -11,7 +11,7 @@ import ( ) func TestFunctionsLoad(t *testing.T) { - generalConfig, err := tc.GetConfig(tc.NoKey, tc.Functions) + generalConfig, err := tc.GetConfig([]string{""}, tc.Functions) require.NoError(t, err, "failed to get config") ft, err := SetupLocalLoadTestEnv(&generalConfig, &generalConfig) @@ -25,7 +25,7 @@ func TestFunctionsLoad(t *testing.T) { MonitorLoadStats(t, ft, labels, &generalConfig) t.Run("mumbai functions soak test http", func(t *testing.T) { - config, err := tc.GetConfig("Soak", tc.Functions) + config, err := tc.GetConfig([]string{"Soak"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki @@ -59,7 +59,7 @@ func TestFunctionsLoad(t *testing.T) { }) t.Run("mumbai functions stress test http", func(t *testing.T) { - config, err := tc.GetConfig("Stress", tc.Functions) + config, err := tc.GetConfig([]string{"Stress"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki @@ -93,7 +93,7 @@ func TestFunctionsLoad(t *testing.T) { }) t.Run("mumbai functions soak test only secrets", func(t *testing.T) { - config, err := tc.GetConfig("SecretsSoak", tc.Functions) + config, err := tc.GetConfig([]string{"SecretsSoak"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki @@ -127,7 +127,7 @@ func TestFunctionsLoad(t *testing.T) { }) t.Run("mumbai functions stress test only secrets", func(t *testing.T) { - config, err := tc.GetConfig("SecretsStress", tc.Functions) + config, err := tc.GetConfig([]string{"SecretsStress"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki @@ -161,7 +161,7 @@ func TestFunctionsLoad(t *testing.T) { }) t.Run("mumbai functions soak test real", func(t *testing.T) { - config, err := tc.GetConfig("RealSoak", tc.Functions) + config, err := tc.GetConfig([]string{"RealSoak"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki @@ -195,7 +195,7 @@ func TestFunctionsLoad(t *testing.T) { }) t.Run("mumbai functions stress test real", func(t *testing.T) { - config, err := tc.GetConfig("RealStress", tc.Functions) + config, err := tc.GetConfig([]string{"RealStress"}, tc.Functions) require.NoError(t, err, "failed to get config") cfg := config.Functions cfgl := config.Logging.Loki diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index c2d5bd7c2cd..dd1092a595c 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -11,7 +11,7 @@ import ( ) func TestGatewayLoad(t *testing.T) { - listConfig, err := tc.GetConfig("GatewayList", tc.Functions) + listConfig, err := tc.GetConfig([]string{"GatewayList"}, tc.Functions) require.NoError(t, err) cfgl := listConfig.Logging.Loki @@ -42,7 +42,7 @@ func TestGatewayLoad(t *testing.T) { LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), } - setConfig, err := tc.GetConfig("GatewaySet", tc.Functions) + setConfig, err := tc.GetConfig([]string{"GatewaySet"}, tc.Functions) require.NoError(t, err) secretsSetCfg := &wasp.Config{ diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index de431a463ca..bc2327b4a6c 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,11 +16,11 @@ require ( github.com/rs/zerolog v1.31.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf - github.com/smartcontractkit/chainlink-testing-framework v1.31.4 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe + github.com/smartcontractkit/chainlink-testing-framework v1.31.7 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 - github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c + github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e github.com/smartcontractkit/seth v1.0.12 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.4.7 @@ -372,15 +372,14 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d // indirect - github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba // indirect github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 // indirect - github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect - github.com/smartcontractkit/wsrpc v0.8.1 // indirect + github.com/smartcontractkit/wsrpc v0.7.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/afero v1.9.5 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index c77d1a1f27e..b6067ca0018 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -813,6 +813,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1502,30 +1503,28 @@ 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.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf h1:d9AS/K8RSVG64USb20N/U7RaPOsYPcmuLGJq7iE+caM= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf/go.mod h1:L32xvCpk84Nglit64OhySPMP1tM3TTBK7Tw0qZl7Sd4= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d h1:5tgMC5Gi2UAOKZ+m28W8ubjLeR0pQCAcrz6eQ0rW510= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240524214833-c362c2ebbd2d/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= -github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540/go.mod h1:sjAmX8K2kbQhvDarZE1ZZgDgmHJ50s0BBc/66vKY2ek= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe h1:lYyWmjheglMu0y3JmfSqs9Dm4tZO34RmbUTOtQ4CadE= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240702120320-563bf07487fe/go.mod h1:EWvSuqIJUYXZLEHewC7WCaPylM2jyjF3Q36BZPS4MoI= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141 h1:TMOoYaeSDkkI3jkCH7lKHOZaLkeDuxFTNC+XblD6M0M= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240621143432-85370a54b141/go.mod h1:0UNuO3nDt9MFsZPaHJBEUolxVkN0iC69j1ccDp95e8k= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527 h1:Vs6myS+bpPwb8chUY7XxveJyhvejknhOmhDTddgsK5I= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240702144807-761f63e7b527/go.mod h1:KRK7KlAEpmORi+nJgT0vxQVWvlLEBQ6zgzXziZuKvUM= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917 h1:MD80ZRCTvxxJ8PBmhtrKoTnky8cVNYrCrIBLVRbrOM0= github.com/smartcontractkit/chainlink-feeds v0.0.0-20240522213638-159fb2d99917/go.mod h1:jwVxhctE6BgLOSSsVq9wbREpZ8Ev34H+UBxeUhESZRs= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9 h1:YudTCEe/2xWdfPY/ESSiPFW4MVsrAoi2MWPwRUJ6QAA= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240625135745-60e0e43656f9/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401 h1:640M3TP06nBckEVqRZljcG/7AJlBxJ6vLXTHy6xCtwE= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240703132526-6362ffb96401/go.mod h1:NbXXQaNFskVMYRut0MvBlcHu/vDgipGMwYjamvjVB9Y= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba h1:YNSlhK5mobyAaw02LPGgIEuS3lXyCTXcc6oaV2L6uUI= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240625074951-06ab5e670dba/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU= -github.com/smartcontractkit/chainlink-testing-framework v1.31.4 h1:5/zF5Z2w+/HTvUSSJNhWSiHvlQ2O2qxRw4e1fBbVraQ= -github.com/smartcontractkit/chainlink-testing-framework v1.31.4/go.mod h1:E6uNEZhZZid9PHv6/Kq5Vn63GlO61ZcKB+/f0DKo3Q4= +github.com/smartcontractkit/chainlink-testing-framework v1.31.7 h1:Vy4ah8VAfj+Y7vVmhjvwyAO6wG+Fp2vzdkSJwJPMQO4= +github.com/smartcontractkit/chainlink-testing-framework v1.31.7/go.mod h1:E6uNEZhZZid9PHv6/Kq5Vn63GlO61ZcKB+/f0DKo3Q4= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 h1:Kk5OVlx/5g9q3Z3lhxytZS4/f8ds1MiNM8yaHgK3Oe8= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU= -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= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= -github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e h1:9ypZ/8aW8Vm497i1gXHcT96oNLiu88jbg9QdX+IUE3E= +github.com/smartcontractkit/libocr v0.0.0-20240702141926-063ceef8c42e/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/smartcontractkit/seth v1.0.12 h1:iVdgMx42XWanPPnBaM5StR4c1XsTr/0/B/kKRZL5BsY= github.com/smartcontractkit/seth v1.0.12/go.mod h1:thWtbLyW4nRHJGzC5heknQDORoJPErE15sF34LHkorg= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= @@ -1534,8 +1533,8 @@ github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:D github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw= github.com/smartcontractkit/wasp v0.4.7 h1:7mKJfwzFbuE8xVLUYtLt7Bjw8q/bmVZRW6Ks8kc1LVM= github.com/smartcontractkit/wasp v0.4.7/go.mod h1:jeabvyXikb2aNoLQwcZGqaz17efrR8NJhpq4seAmdgs= -github.com/smartcontractkit/wsrpc v0.8.1 h1:kk0SXLqWrWaZ3J6c7n8D0NZ2uTMBBBpG5dZZXZX8UGE= -github.com/smartcontractkit/wsrpc v0.8.1/go.mod h1:yfg8v8fPLXkb6Mcnx6Pm/snP6jJ0r5Kf762Yd1a/KpA= +github.com/smartcontractkit/wsrpc v0.7.3 h1:CKYZfawZShZGfvsQep1F9oBansnFk9ByZPCdTMpLphw= +github.com/smartcontractkit/wsrpc v0.7.3/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1717,7 +1716,6 @@ go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0= go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= -go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= @@ -1802,6 +1800,7 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index e63828a7d93..ad0df73218e 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -1,28 +1,31 @@ ### OCR Load tests -## Setup -These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) - -Create your cluster, if you already have one just use `kubefwd` -``` -kubectl create ns cl-cluster -devspace use namespace cl-cluster -devspace deploy -sudo kubefwd svc -n cl-cluster +## Setup CRIB +CRIB CORE user documentation is available in [CORE CRIB - Deploy & Access Instructions](https://smartcontract-it.atlassian.net/wiki/spaces/TT/pages/597197209/CORE+CRIB+-+Deploy+Access+Instructions) +```shell +devspace deploy --debug --profile local-dev-simulated-core-ocr1 --skip-build ``` -Change environment connection configuration [here](../../../charts/chainlink-cluster/connect.toml) - -If you haven't changed anything in [devspace.yaml](../../crib/devspace.yaml) then default connection configuration will work - ## Usage +Create `overrides.toml` in this directory +```toml +[CRIB] +namespace = "$your_crib_namespace_here" +# only Geth is supported right now +network_name = "geth" +nodes = 5 + +[Logging.Loki] +tenant_id="promtail" +endpoint="..." +basic_auth_secret="..." ``` -export LOKI_TOKEN=... -export LOKI_URL=... +Run the tests +Set `K8S_STAGING_INGRESS_SUFFIX` when run locally (`export K8S_STAGING_INGRESS_SUFFIX=$(op read op://CRIB/secrets/K8S_STAGING_INGRESS_SUFFIX)`) + +``` go test -v -run TestOCRLoad go test -v -run TestOCRVolume -``` - -Check test configuration [here](config.toml) \ No newline at end of file +``` \ No newline at end of file diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 15f52acbffa..8d4638f9771 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -3,15 +3,13 @@ package ocr import ( "testing" - seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/integration-tests/k8s" + "github.com/smartcontractkit/chainlink/integration-tests/crib" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -25,18 +23,15 @@ var ( func TestOCRLoad(t *testing.T) { l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Load", tc.OCR) + config, err := tc.GetConfig([]string{"Load"}, tc.OCR) require.NoError(t, err) - evmNetwork, msClient, bootstrapNode, workerNodes, err := k8s.ConnectRemote() + sethClient, msClient, bootstrapNode, workerNodes, err := crib.ConnectRemote(true) require.NoError(t, err) - seth, err := seth_utils.GetChainClient(config, *evmNetwork) - require.NoError(t, err, "Error creating seth client") - - lta, err := SetupCluster(l, seth, workerNodes) + lta, err := SetupCluster(l, sethClient, workerNodes) require.NoError(t, err) - ocrInstances, err := SetupFeed(l, seth, lta, msClient, bootstrapNode, workerNodes) + ocrInstances, err := SetupFeed(l, sethClient, lta, msClient, bootstrapNode, workerNodes) require.NoError(t, err) cfg := config.OCR @@ -51,7 +46,7 @@ func TestOCRLoad(t *testing.T) { CallTimeout: cfg.Load.VerificationTimeout.Duration, RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration, Schedule: wasp.Plain(*cfg.Load.Rate, cfg.Load.TestDuration.Duration), - Gun: NewGun(l, seth, ocrInstances), + Gun: NewGun(l, sethClient, ocrInstances), Labels: CommonTestLabels, LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) @@ -61,16 +56,13 @@ func TestOCRLoad(t *testing.T) { func TestOCRVolume(t *testing.T) { l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Volume", tc.OCR) + config, err := tc.GetConfig([]string{"Volume"}, tc.OCR) require.NoError(t, err) - evmNetwork, msClient, bootstrapNode, workerNodes, err := k8s.ConnectRemote() + sethClient, msClient, bootstrapNode, workerNodes, err := crib.ConnectRemote(true) require.NoError(t, err) - seth, err := seth_utils.GetChainClient(config, *evmNetwork) - require.NoError(t, err, "Error creating seth client") - - lta, err := SetupCluster(l, seth, workerNodes) + lta, err := SetupCluster(l, sethClient, workerNodes) require.NoError(t, err) cfg := config.OCR @@ -83,7 +75,7 @@ func TestOCRVolume(t *testing.T) { LoadType: wasp.VU, CallTimeout: cfg.Volume.VerificationTimeout.Duration, Schedule: wasp.Plain(*cfg.Volume.Rate, cfg.Volume.TestDuration.Duration), - VU: NewVU(l, seth, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, lta, bootstrapNode, workerNodes, msClient), + VU: NewVU(l, sethClient, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, lta, bootstrapNode, workerNodes, msClient), Labels: CommonTestLabels, LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 5f7e184a488..0a014ccc44a 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -46,7 +46,7 @@ func TestVRFV2Performance(t *testing.T) { l := logging.GetTestLogger(t) testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - testConfig, err := tc.GetConfig(testType, tc.VRFv2) + testConfig, err := tc.GetChainAndTestTypeSpecificConfig(testType, tc.VRFv2) require.NoError(t, err) cfgl := testConfig.Logging.Loki @@ -188,7 +188,7 @@ func TestVRFV2BHSPerformance(t *testing.T) { testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - testConfig, err := tc.GetConfig(testType, tc.VRFv2) + testConfig, err := tc.GetChainAndTestTypeSpecificConfig(testType, tc.VRFv2) require.NoError(t, err) vrfv2Config := testConfig.VRFv2 testReporter := &testreporters.VRFV2TestReporter{} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 3ff9a12996e..3835dbfb616 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -45,7 +45,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { l := logging.GetTestLogger(t) testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) + testConfig, err := tc.GetChainAndTestTypeSpecificConfig(testType, tc.VRFv2Plus) require.NoError(t, err) cfgl := testConfig.Logging.Loki @@ -188,7 +188,7 @@ func TestVRFV2PlusBHSPerformance(t *testing.T) { testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) + testConfig, err := tc.GetChainAndTestTypeSpecificConfig(testType, tc.VRFv2Plus) require.NoError(t, err) vrfv2PlusConfig := testConfig.VRFv2Plus testReporter := &testreporters.VRFV2PlusTestReporter{} diff --git a/integration-tests/load/zcluster/cluster_entrypoint_test.go b/integration-tests/load/zcluster/cluster_entrypoint_test.go index 35b3ee422ca..aace97b0825 100644 --- a/integration-tests/load/zcluster/cluster_entrypoint_test.go +++ b/integration-tests/load/zcluster/cluster_entrypoint_test.go @@ -10,7 +10,7 @@ import ( ) func TestClusterEntrypoint(t *testing.T) { - config, err := tc.GetConfig("Load", tc.OCR) + config, err := tc.GetConfig([]string{"Load"}, tc.OCR) require.NoError(t, err) cfgBase64, err := config.AsBase64() require.NoError(t, err) diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index 4c7b275e299..a17f00e179f 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -17,7 +17,7 @@ func TestVersionUpgrade(t *testing.T) { l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Migration", tc.Node) + config, err := tc.GetConfig([]string{"Migration"}, tc.Node) require.NoError(t, err, "Error getting config") err = config.ChainlinkUpgradeImage.Validate() diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index 958923327ae..2a2350e1956 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -84,7 +84,7 @@ var ( * Upkeeps are expected to be performed during the reorg. */ func TestAutomationReorg(t *testing.T) { - c, err := tc.GetConfig("Reorg", tc.Automation) + c, err := tc.GetConfig([]string{"Reorg"}, tc.Automation) require.NoError(t, err, "Error getting config") findIntValue := func(text string, substring string) (int, error) { @@ -126,7 +126,7 @@ func TestAutomationReorg(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - config, err := tc.GetConfig("Reorg", tc.Automation) + config, err := tc.GetConfig([]string{"Reorg"}, tc.Automation) if err != nil { t.Fatal(err) } @@ -229,6 +229,8 @@ func TestAutomationReorg(t *testing.T) { defaultUpkeepGasLimit, isLogTrigger, false, + false, + nil, ) if isLogTrigger { diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 46abccae565..62462d641a8 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strconv" + "strings" "testing" "time" @@ -98,19 +99,25 @@ func TestAutomationBasic(t *testing.T) { func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { t.Parallel() + // native, mercury_v02, mercury_v03 and logtrigger are reserved keywords, use them with caution registryVersions := map[string]ethereum.KeeperRegistryVersion{ - "registry_2_0": ethereum.RegistryVersion_2_0, - "registry_2_1_conditional": ethereum.RegistryVersion_2_1, - "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, - "registry_2_1_with_mercury_v02": ethereum.RegistryVersion_2_1, - "registry_2_1_with_mercury_v03": ethereum.RegistryVersion_2_1, - "registry_2_1_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_1, - "registry_2_2_conditional": ethereum.RegistryVersion_2_2, - "registry_2_2_logtrigger": ethereum.RegistryVersion_2_2, - "registry_2_2_with_mercury_v02": ethereum.RegistryVersion_2_2, - "registry_2_2_with_mercury_v03": ethereum.RegistryVersion_2_2, - "registry_2_2_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_2, - "registry_2_3_conditional": ethereum.RegistryVersion_2_3, + "registry_2_0": ethereum.RegistryVersion_2_0, + "registry_2_1_conditional": ethereum.RegistryVersion_2_1, + "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, + "registry_2_1_with_mercury_v02": ethereum.RegistryVersion_2_1, + "registry_2_1_with_mercury_v03": ethereum.RegistryVersion_2_1, + "registry_2_1_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_1, + "registry_2_2_conditional": ethereum.RegistryVersion_2_2, + "registry_2_2_logtrigger": ethereum.RegistryVersion_2_2, + "registry_2_2_with_mercury_v02": ethereum.RegistryVersion_2_2, + "registry_2_2_with_mercury_v03": ethereum.RegistryVersion_2_2, + "registry_2_2_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_2, + "registry_2_3_conditional_native": ethereum.RegistryVersion_2_3, + "registry_2_3_conditional_link": ethereum.RegistryVersion_2_3, + "registry_2_3_logtrigger_native": ethereum.RegistryVersion_2_3, + "registry_2_3_logtrigger_link": ethereum.RegistryVersion_2_3, + "registry_2_3_with_mercury_v03_link": ethereum.RegistryVersion_2_3, + "registry_2_3_with_logtrigger_and_mercury_v02_link": ethereum.RegistryVersion_2_3, } for n, rv := range registryVersions { @@ -120,7 +127,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { t.Parallel() l := logging.GetTestLogger(t) - cfg, err := tc.GetConfig("Smoke", tc.Automation) + cfg, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") if nodeUpgrade { @@ -129,10 +136,11 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { } } - // Use the name to determine if this is a log trigger or mercury - isLogTrigger := name == "registry_2_1_logtrigger" || name == "registry_2_1_with_logtrigger_and_mercury_v02" || name == "registry_2_2_logtrigger" || name == "registry_2_2_with_logtrigger_and_mercury_v02" - isMercuryV02 := name == "registry_2_1_with_mercury_v02" || name == "registry_2_1_with_logtrigger_and_mercury_v02" || name == "registry_2_2_with_mercury_v02" || name == "registry_2_2_with_logtrigger_and_mercury_v02" - isMercuryV03 := name == "registry_2_1_with_mercury_v03" || name == "registry_2_2_with_mercury_v03" + // Use the name to determine if this is a log trigger or mercury or billing token is native + isBillingTokenNative := strings.Contains(name, "native") + isLogTrigger := strings.Contains(name, "logtrigger") + isMercuryV02 := strings.Contains(name, "mercury_v02") + isMercuryV03 := strings.Contains(name, "mercury_v03") isMercury := isMercuryV02 || isMercuryV03 a := setupAutomationTestDocker( @@ -153,6 +161,8 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { automationDefaultUpkeepGasLimit, isLogTrigger, isMercury, + isBillingTokenNative, + a.WETHToken, ) // Do it in two separate loops, so we don't end up setting up one upkeep, but starting the consumer for another one @@ -189,8 +199,6 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() }) - // TODO Tune this timeout window after stress testing - l.Info().Msg("Waiting 10m for all upkeeps to perform at least 1 upkeep") gom.Eventually(func(g gomega.Gomega) { // Check if the upkeeps are performing multiple times by analyzing their counters for i := 0; i < len(upkeepIDs); i++ { @@ -271,7 +279,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -292,6 +300,8 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { automationDefaultUpkeepGasLimit, true, false, + false, + nil, ) // Start log trigger based upkeeps for all consumers @@ -453,7 +463,7 @@ func TestAutomationAddFunds(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, @@ -473,6 +483,8 @@ func TestAutomationAddFunds(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { @@ -530,7 +542,7 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -551,6 +563,8 @@ func TestAutomationPauseUnPause(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { @@ -629,7 +643,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -650,6 +664,8 @@ func TestAutomationRegisterUpkeep(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { @@ -723,7 +739,7 @@ func TestAutomationPauseRegistry(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -744,6 +760,8 @@ func TestAutomationPauseRegistry(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { @@ -801,7 +819,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -822,6 +840,8 @@ func TestAutomationKeeperNodesDown(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { @@ -907,7 +927,7 @@ func TestAutomationPerformSimulation(t *testing.T) { registryVersion := rv t.Run(name, func(t *testing.T) { t.Parallel() - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -979,7 +999,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, @@ -1133,7 +1153,7 @@ func TestUpdateCheckData(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) require.NoError(t, err, "Failed to get config") a := setupAutomationTestDocker( @@ -1213,7 +1233,7 @@ func TestSetOffchainConfigWithMaxGasPrice(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Automation) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Automation) if err != nil { t.Fatal(err) } @@ -1235,6 +1255,8 @@ func TestSetOffchainConfigWithMaxGasPrice(t *testing.T) { automationDefaultUpkeepGasLimit, false, false, + false, + nil, ) t.Cleanup(func() { diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index f0b8a1cb603..1b8477ca289 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -37,9 +37,26 @@ }, { "name": "TestAutomationBasic", - "nodes": 1, + "nodes": 2, + "run":[ + {"name":"registry_2_3_conditional_native"}, + {"name":"registry_2_3_conditional_link"} + ] + }, + { + "name": "TestAutomationBasic", + "nodes": 2, + "run":[ + {"name":"registry_2_3_logtrigger_native"}, + {"name":"registry_2_3_logtrigger_link"} + ] + }, + { + "name": "TestAutomationBasic", + "nodes": 2, "run":[ - {"name":"registry_2_3_conditional"} + {"name":"registry_2_3_with_mercury_v03_link"}, + {"name":"registry_2_3_with_logtrigger_and_mercury_v02_link"} ] }, { diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 6f864b2e49f..98c1fe0caf7 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -21,7 +21,7 @@ func TestCronBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Cron) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Cron) if err != nil { t.Fatal(err) } @@ -76,7 +76,7 @@ func TestCronJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Cron) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Cron) if err != nil { t.Fatal(err) } diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 05b75da2237..d8773690b23 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -27,7 +27,7 @@ func TestFluxBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Flux) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Flux) require.NoError(t, err, "Error getting config") privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 0377553191b..a249775dc6a 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -24,7 +24,7 @@ func TestForwarderOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.ForwarderOcr) + config, err := tc.GetConfig([]string{"Smoke"}, tc.ForwarderOcr) require.NoError(t, err, "Error getting config") privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 3970a0b43b1..863b36e4ede 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -25,7 +25,7 @@ func TestForwarderOCR2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.ForwarderOcr2) + config, err := tc.GetConfig([]string{"Smoke"}, tc.ForwarderOcr2) require.NoError(t, err, "Error getting config") privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 21e1aa6e08f..4ff1c90bd1e 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -89,7 +89,7 @@ func TestKeeperBasicSmoke(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -170,7 +170,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -314,7 +314,7 @@ func TestKeeperSimulation(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -393,7 +393,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -530,7 +530,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -626,7 +626,7 @@ func TestKeeperAddFunds(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -701,7 +701,7 @@ func TestKeeperRemove(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -786,7 +786,7 @@ func TestKeeperPauseRegistry(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -853,7 +853,7 @@ func TestKeeperPauseRegistry(t *testing.T) { func TestKeeperMigrateRegistry(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Error getting config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -956,7 +956,7 @@ func TestKeeperNodeDown(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -1066,7 +1066,7 @@ type nodeAndJob struct { func TestKeeperPauseUnPauseUpkeep(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -1158,7 +1158,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { func TestKeeperUpdateCheckData(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) @@ -1264,7 +1264,7 @@ func TestKeeperJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) registryVersion := ethereum.RegistryVersion_1_3 - config, err := tc.GetConfig("Smoke", tc.Keeper) + config, err := tc.GetConfig([]string{"Smoke"}, tc.Keeper) require.NoError(t, err, "Failed to get config") chainClient, chainlinkNodes, linkToken, _ := setupKeeperTest(l, t, &config) diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index 05be29a90bc..f1a257552a2 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -91,7 +91,7 @@ func TestLogPollerReplayFinalityTag(t *testing.T) { // HELPER FUNCTIONS func executeBasicLogPollerTest(t *testing.T, logScannerSettings test_env.ChainlinkNodeLogScannerSettings) { - testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + testConfig, err := tc.GetConfig([]string{t.Name()}, tc.LogPoller) require.NoError(t, err, "Error getting config") overrideEphemeralAddressesCount(&testConfig) @@ -174,7 +174,7 @@ func executeBasicLogPollerTest(t *testing.T, logScannerSettings test_env.Chainli } func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { - testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + testConfig, err := tc.GetConfig([]string{t.Name()}, tc.LogPoller) require.NoError(t, err, "Error getting config") overrideEphemeralAddressesCount(&testConfig) @@ -317,6 +317,8 @@ func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfi uint32(2500000), true, false, + false, + nil, ) err = logpoller.AssertUpkeepIdsUniqueness(upkeepIDs) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 09a9a222494..56a95c50bda 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -139,7 +139,7 @@ func TestOCRv2JobReplacement(t *testing.T) { } func prepareORCv2SmokeTestEnv(t *testing.T, testData ocr2test, l zerolog.Logger, firstRoundResult int) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregatorV2, *seth.Client) { - config, err := tc.GetConfig("Smoke", tc.OCR2) + config, err := tc.GetConfig([]string{"Smoke"}, tc.OCR2) if err != nil { t.Fatal(err) } diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go deleted file mode 100644 index 5b263dc1445..00000000000 --- a/integration-tests/smoke/ocr2vrf_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package smoke - -import ( - "fmt" - "math/big" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testconfig" -) - -var ocr2vrfSmokeConfig *testconfig.TestConfig - -func TestOCR2VRFRedeemModel(t *testing.T) { - t.Parallel() - // remember to add TOML testConfig for Chainlink node before trying to run this test in future - t.Skip("VRFv3 is on pause, skipping") - l := logging.GetTestLogger(t) - testConfig, err := testconfig.GetConfig("Smoke", testconfig.OCR2VRF) - require.NoError(t, err, "Error getting config") - - testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - testNetwork = seth_utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) - chainClient, err := seth_utils.GetChainClientWithConfigFunction(testConfig, testNetwork, seth_utils.OneEphemeralKeysLiveTestnetCheckFn) - require.NoError(t, err, "Error creating seth client") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) - require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - - t.Cleanup(func() { - err := actions.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &testConfig) - require.NoError(t, err, "Error tearing down environment") - }) - - linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) - require.NoError(t, err, "Error deploying LINK token") - - mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) - require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") - - _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( - t, - linkToken, - mockETHLinkFeed, - chainClient, - nodeAddresses, - chainlinkNodes, - testNetwork, - ) - - //Request and Redeem Randomness - requestID := ocr2vrf_actions.RequestAndRedeemRandomness( - t, - consumerContract, - vrfBeaconContract, - ocr2vrf_constants.NumberOfRandomWordsToRequest, - subID, - ocr2vrf_constants.ConfirmationDelay, - ocr2vrf_constants.RandomnessRedeemTransmissionEventTimeout, - ) - - for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) - require.NoError(t, err) - l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness retrieved from Consumer contract") - require.NotEqual(t, 0, randomness.Uint64(), "Randomness retrieved from Consumer contract give an answer other than 0") - } -} - -func TestOCR2VRFFulfillmentModel(t *testing.T) { - t.Parallel() - t.Skip("VRFv3 is on pause, skipping") - l := logging.GetTestLogger(t) - testConfig, err := testconfig.GetConfig("Smoke", testconfig.OCR2VRF) - require.NoError(t, err, "Error getting config") - - testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - testNetwork = seth_utils.MustReplaceSimulatedNetworkUrlWithK8(l, testNetwork, *testEnvironment) - chainClient, err := seth_utils.GetChainClientWithConfigFunction(testConfig, testNetwork, seth_utils.OneEphemeralKeysLiveTestnetCheckFn) - require.NoError(t, err, "Error creating seth client") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) - require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - - t.Cleanup(func() { - err := actions.TeardownSuite(t, chainClient, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &testConfig) - require.NoError(t, err, "Error tearing down environment") - }) - - linkToken, err := contracts.DeployLinkTokenContract(l, chainClient) - require.NoError(t, err, "Error deploying LINK token") - - mockETHLinkFeed, err := contracts.DeployMockETHLINKFeed(chainClient, ocr2vrf_constants.LinkEthFeedResponse) - require.NoError(t, err, "Error deploying Mock ETH/LINK Feed") - - _, _, vrfBeaconContract, consumerContract, subID := ocr2vrf_actions.SetupOCR2VRFUniverse( - t, - linkToken, - mockETHLinkFeed, - chainClient, - nodeAddresses, - chainlinkNodes, - testNetwork, - ) - - requestID := ocr2vrf_actions.RequestRandomnessFulfillmentAndWaitForFulfilment( - t, - consumerContract, - vrfBeaconContract, - ocr2vrf_constants.NumberOfRandomWordsToRequest, - subID, - ocr2vrf_constants.ConfirmationDelay, - ocr2vrf_constants.RandomnessFulfilmentTransmissionEventTimeout, - ) - - for i := uint16(0); i < ocr2vrf_constants.NumberOfRandomWordsToRequest; i++ { - randomness, err := consumerContract.GetRandomnessByRequestId(testcontext.Get(t), requestID, big.NewInt(int64(i))) - require.NoError(t, err, "Error getting Randomness result from Consumer Contract") - l.Info().Interface("Random Number", randomness).Interface("Randomness Number Index", i).Msg("Randomness Fulfillment retrieved from Consumer contract") - require.NotEqual(t, 0, randomness.Uint64(), "Randomness Fulfillment retrieved from Consumer contract give an answer other than 0") - } -} - -func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - if ocr2vrfSmokeConfig == nil { - c, err := testconfig.GetConfig("Smoke", testconfig.OCR2VRF) - require.NoError(t, err, "Error getting config") - ocr2vrfSmokeConfig = &c - } - - testNetwork = networks.MustGetSelectedNetworkConfig(ocr2vrfSmokeConfig.Network)[0] - evmConfig := eth.New(nil) - if !testNetwork.Simulated { - evmConfig = eth.New(ð.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - - var overrideFn = func(_ interface{}, target interface{}) { - ctf_config.MustConfigOverrideChainlinkVersion(ocr2vrfSmokeConfig.GetChainlinkImageConfig(), target) - ctf_config.MightConfigOverridePyroscopeKey(ocr2vrfSmokeConfig.GetPyroscopeConfig(), target) - } - - tomlConfig, err := actions.BuildTOMLNodeConfigForK8s(ocr2vrfSmokeConfig, testNetwork) - require.NoError(t, err, "Error building TOML config") - - cd := chainlink.NewWithOverride(0, map[string]interface{}{ - "replicas": 6, - "toml": tomlConfig, - }, ocr2vrfSmokeConfig.ChainlinkImage, overrideFn) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-ocr2vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - }). - AddHelm(evmConfig). - AddHelm(cd) - err = testEnvironment.Run() - - require.NoError(t, err, "Error running test environment") - - return testEnvironment, testNetwork -} diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index d989517278e..67f8c44f8a1 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -80,7 +80,7 @@ func TestOCRJobReplacement(t *testing.T) { } func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int64) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregator, *seth.Client) { - config, err := tc.GetConfig("Smoke", tc.OCR) + config, err := tc.GetConfig([]string{"Smoke"}, tc.OCR) if err != nil { t.Fatal(err) } diff --git a/integration-tests/smoke/reorg_above_finality_test.go b/integration-tests/smoke/reorg_above_finality_test.go index 829aa66fdce..e7b9e4a2183 100644 --- a/integration-tests/smoke/reorg_above_finality_test.go +++ b/integration-tests/smoke/reorg_above_finality_test.go @@ -19,7 +19,7 @@ func TestReorgAboveFinality_FinalityTagDisabled(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig(t.Name(), tc.LogPoller) + config, err := tc.GetConfig([]string{t.Name()}, tc.LogPoller) require.NoError(t, err, "Error getting config") privateNetworkConf, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 862ac911b36..515d9dea33c 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -28,7 +28,7 @@ func TestRunLogBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.RunLog) + config, err := tc.GetConfig([]string{"Smoke"}, tc.RunLog) require.NoError(t, err, "Error getting config") privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 0f706f1576b..04e760796db 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -186,7 +186,7 @@ func TestVRFJobReplacement(t *testing.T) { } func prepareVRFtestEnv(t *testing.T, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfv1.Contracts, *seth.Client) { - config, err := tc.GetConfig("Smoke", tc.VRF) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRF) require.NoError(t, err, "Error getting config") privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 70fcb4bcf7d..0cf04051e7c 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -52,7 +52,7 @@ func TestVRFv2Basic(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") vrfv2Config := config.VRFv2 chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -569,7 +569,7 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) if err != nil { t.Fatal(err) } @@ -677,7 +677,7 @@ func TestVRFOwner(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID vrfv2Config := config.VRFv2 @@ -813,7 +813,7 @@ func TestVRFV2WithBHS(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") vrfv2Config := config.VRFv2 chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1031,7 +1031,7 @@ func TestVRFV2NodeReorg(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") vrfv2Config := config.VRFv2 network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] @@ -1210,7 +1210,7 @@ func TestVRFv2BatchFulfillmentEnabledDisabled(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") vrfv2Config := config.VRFv2 network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index b713cdf9409..106b4f3c1c9 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -49,8 +49,9 @@ func TestVRFv2Plus(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -746,7 +747,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -851,7 +852,7 @@ func TestVRFv2PlusMigration(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1245,7 +1246,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1474,7 +1475,7 @@ func TestVRFV2PlusWithBHF(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1631,7 +1632,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1800,7 +1801,7 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID @@ -1894,7 +1895,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] @@ -2071,7 +2072,7 @@ func TestVRFv2PlusBatchFulfillmentEnabledDisabled(t *testing.T) { ) l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + config, err := tc.GetChainAndTestTypeSpecificConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") vrfv2PlusConfig := config.VRFv2Plus network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go index fa9752a9a9c..dd7eb102170 100644 --- a/integration-tests/soak/forwarder_ocr_test.go +++ b/integration-tests/soak/forwarder_ocr_test.go @@ -15,7 +15,7 @@ import ( func TestForwarderOCRv1Soak(t *testing.T) { //nolint:revive t.Fatalf("This test is disabled because the implementation is broken") - config, err := tc.GetConfig("Soak", tc.ForwarderOcr) + config, err := tc.GetConfig([]string{"Soak"}, tc.ForwarderOcr) require.NoError(t, err, "Error getting config") executeForwarderOCRSoakTest(t, &config) @@ -24,7 +24,7 @@ func TestForwarderOCRv1Soak(t *testing.T) { func TestForwarderOCRv2Soak(t *testing.T) { //nolint:revive t.Fatalf("This test is disabled because the implementation is broken") - config, err := tc.GetConfig("Soak", tc.ForwarderOcr2) + config, err := tc.GetConfig([]string{"Soak"}, tc.ForwarderOcr2) require.NoError(t, err, "Error getting config") executeForwarderOCRSoakTest(t, &config) diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index 0e7b50d15b5..1f437e565eb 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -25,7 +25,7 @@ import ( ) func TestOCRv1Soak(t *testing.T) { - config, err := tc.GetConfig("Soak", tc.OCR) + config, err := tc.GetConfig([]string{"Soak"}, tc.OCR) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) require.NoError(t, err, "Error creating OCR soak test") @@ -33,7 +33,7 @@ func TestOCRv1Soak(t *testing.T) { } func TestOCRv2Soak(t *testing.T) { - config, err := tc.GetConfig("Soak", tc.OCR2) + config, err := tc.GetConfig([]string{"Soak"}, tc.OCR2) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) @@ -42,7 +42,7 @@ func TestOCRv2Soak(t *testing.T) { } func TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) require.NoError(t, err, "Error creating OCR soak test") @@ -50,7 +50,7 @@ func TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled(t *testing.T) { } func TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) require.NoError(t, err, "Error creating OCR soak test") @@ -58,7 +58,7 @@ func TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled(t *testing.T) { } func TestOCRSoak_GasSpike(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) require.NoError(t, err, "Error creating OCR soak test") @@ -67,7 +67,7 @@ func TestOCRSoak_GasSpike(t *testing.T) { // TestOCRSoak_ChangeBlockGasLimit changes next block gas limit and sets it to percentage of last gasUsed in previous block creating congestion func TestOCRSoak_ChangeBlockGasLimit(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config) require.NoError(t, err, "Error creating OCR soak test") @@ -76,7 +76,7 @@ func TestOCRSoak_ChangeBlockGasLimit(t *testing.T) { // TestOCRSoak_RPCDownForAllCLNodes simulates a network chaos by bringing down network to RPC node for all Chainlink Nodes func TestOCRSoak_RPCDownForAllCLNodes(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") require.True(t, config.Network.IsSimulatedGethSelected(), "This test requires simulated geth") @@ -108,7 +108,7 @@ func TestOCRSoak_RPCDownForAllCLNodes(t *testing.T) { // TestOCRSoak_RPCDownForAllCLNodes simulates a network chaos by bringing down network to RPC node for 50% of Chainlink Nodes func TestOCRSoak_RPCDownForHalfCLNodes(t *testing.T) { - config, err := tc.GetConfig(t.Name(), tc.OCR) + config, err := tc.GetConfig([]string{t.Name()}, tc.OCR) require.NoError(t, err, "Error getting config") require.True(t, config.Network.IsSimulatedGethSelected(), "This test requires simulated geth") @@ -149,9 +149,6 @@ func executeOCRSoakTest(t *testing.T, test *testsetups.OCRSoakTest, config *tc.T require.NoError(t, err, "Error creating seth client") } - if !test.Interrupted() { - test.DeployEnvironment(config) - } l.Info().Str("test", t.Name()).Msg("Starting OCR soak test") if !test.Interrupted() { test.DeployEnvironment(config) diff --git a/integration-tests/testconfig/automation/automation.toml b/integration-tests/testconfig/automation/automation.toml index 2ebe2b7b37c..a30202d0ec7 100644 --- a/integration-tests/testconfig/automation/automation.toml +++ b/integration-tests/testconfig/automation/automation.toml @@ -30,11 +30,6 @@ Unauthenticated = 1000 [WebServer.TLS] HTTPSPort = 0 -[Database] -MaxIdleConns = 20 -MaxOpenConns = 40 -MigrateOnStartup = true - [OCR2] Enabled = true @@ -43,8 +38,6 @@ Enabled = true Enabled = true ListenAddresses = ['0.0.0.0:6690'] AnnounceAddresses = ['0.0.0.0:6690'] -DeltaDial = '500ms' -DeltaReconcile = '5s' """ # smoke test specific overrodes diff --git a/integration-tests/testconfig/configs_embed.go b/integration-tests/testconfig/configs_embed.go index 67e954ff503..31303357a43 100644 --- a/integration-tests/testconfig/configs_embed.go +++ b/integration-tests/testconfig/configs_embed.go @@ -7,11 +7,15 @@ import "embed" //go:embed default.toml //go:embed automation/automation.toml +//go:embed forwarder_ocr/forwarder_ocr.toml +//go:embed forwarder_ocr2/forwarder_ocr2.toml //go:embed functions/functions.toml //go:embed keeper/keeper.toml //go:embed log_poller/log_poller.toml //go:embed node/node.toml //go:embed ocr/ocr.toml +//go:embed ocr2/ocr2.toml +//go:embed vrf/vrf.toml //go:embed vrfv2/vrfv2.toml //go:embed vrfv2plus/vrfv2plus.toml var embeddedConfigsFs embed.FS diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index 397fc2ee792..d317d05bc49 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -80,10 +80,14 @@ DeltaReconcile = '5s' # override config toml related to EVMNode configs for chainlink nodes; applicable to all EVM node configs in chainlink toml CommonChainConfigTOML = """ +""" + +[NodeConfig.ChainConfigTOMLByChainID] +# applicable for simulated chain +1337 = """ AutoCreateKey = true FinalityDepth = 1 MinContractPayment = 0 - [GasEstimator] PriceMax = '200 gwei' LimitDefault = 6000000 diff --git a/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml b/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml index 344736cf90e..8fa0fa5db25 100644 --- a/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml +++ b/integration-tests/testconfig/forwarder_ocr/forwarder_ocr.toml @@ -45,15 +45,6 @@ DeltaReconcile = '5s' """ CommonChainConfigTOML = """ -AutoCreateKey = true -FinalityDepth = 1 -MinContractPayment = 0 - -[GasEstimator] -PriceMax = '200 gwei' -LimitDefault = 6000000 -FeeCapDefault = '200 gwei' - [Transactions] ForwardersEnabled = true """ @@ -101,10 +92,8 @@ chainlink_node_funding = 0.5 [Soak.OCR] [Soak.OCR.Common] -test_duration="15m" +test_duration = "15m" [Soak.OCR.Soak] -number_of_contracts=2 -time_between_rounds="1m" - - +number_of_contracts = 2 +time_between_rounds = "1m" diff --git a/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml b/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml index c7f0084c726..3f2a8610a83 100644 --- a/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml +++ b/integration-tests/testconfig/forwarder_ocr2/forwarder_ocr2.toml @@ -41,15 +41,6 @@ ListenAddresses = ['0.0.0.0:6690'] """ CommonChainConfigTOML = """ -AutoCreateKey = true -FinalityDepth = 1 -MinContractPayment = 0 - -[GasEstimator] -PriceMax = '200 gwei' -LimitDefault = 6000000 -FeeCapDefault = '200 gwei' - [Transactions] ForwardersEnabled = true """ diff --git a/integration-tests/testconfig/keeper/keeper.toml b/integration-tests/testconfig/keeper/keeper.toml index c69f5a5cf7d..b4a6a3b2c0e 100644 --- a/integration-tests/testconfig/keeper/keeper.toml +++ b/integration-tests/testconfig/keeper/keeper.toml @@ -30,11 +30,6 @@ Unauthenticated = 1000 [WebServer.TLS] HTTPSPort = 0 -[Database] -MaxIdleConns = 20 -MaxOpenConns = 40 -MigrateOnStartup = true - [Keeper] TurnLookBack = 0 """ @@ -84,14 +79,6 @@ HTTPWriteTimeout = '1h' """ CommonChainConfigTOML = """ -AutoCreateKey = true -FinalityDepth = 1 -MinContractPayment = 0 - -[GasEstimator] -PriceMax = '200 gwei' -LimitDefault = 6000000 -FeeCapDefault = '200 gwei' """ [Benchmark.NodeConfig.ChainConfigTOMLByChainID] @@ -107,4 +94,4 @@ HistoryDepth = 100 [GasEstimator] Mode = 'FixedPrice' LimitDefault = 5_000_000 -""" \ No newline at end of file +""" diff --git a/integration-tests/testconfig/ocr2vrf/example.toml b/integration-tests/testconfig/ocr2vrf/example.toml deleted file mode 100644 index 6e7138aeda3..00000000000 --- a/integration-tests/testconfig/ocr2vrf/example.toml +++ /dev/null @@ -1,167 +0,0 @@ -# Example of full config with all fields -# General part -[ChainlinkImage] -image="public.ecr.aws/chainlink/chainlink" -version="2.7.0" - -[Logging] -# if set to true will save logs even if test did not fail -test_log_collect=false - -[Logging.LogStream] -# supported targets: file, loki, in-memory. if empty no logs will be persistet -log_targets=["file"] -# context timeout for starting log producer and also time-frame for requesting logs -log_producer_timeout="10s" -# number of retries before log producer gives up and stops listening to logs -log_producer_retry_limit=10 - -[Logging.Loki] -tenant_id="tenant_id" -# full URL of Loki ingest endpoint -endpoint="https://loki.url/api/v3/push" -# currently only needed when using public instance -basic_auth_secret="loki-basic-auth" -# only needed for cloud grafana -bearer_token_secret="bearer_token" - -# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) -[Logging.Grafana] -# grafana url (trailing "/" will be stripped) -base_url="http://grafana.url" -# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard -dashboard_url="/d/your-dashboard" -bearer_token_secret="my-awesome-token" - -# if you want to use polygon_mumbial -[Network] -selected_networks=["polygon_mumbai"] - -[Network.RpcHttpUrls] -polygon_mumbai = ["https://my-rpc-endpoint.io"] - -[Network.RpcWsUrls] -polygon_mumbai = ["https://my-rpc-endpoint.io"] - -[Network.WalletKeys] -polygon_mumbai = ["change-me-to-your-PK"] - -[PrivateEthereumNetwork] -# pos or pow -consensus_type="pos" -# only prysm supported currently -consensus_layer="prysm" -# geth, besu, nethermind or erigon -execution_layer="geth" -# if true after env started it will wait for at least 1 epoch to be finalised before continuing -wait_for_finalization=false - -[PrivateEthereumNetwork.EthereumChainConfig] -# duration of single slot, lower => faster block production, must be >= 4 -seconds_per_slot=12 -# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 -slots_per_epoch=6 -# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts -genesis_delay=15 -# number of validators in the network -validator_count=8 -chain_id=1337 -# list of addresses to be prefunded in genesis -addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] - -[PrivateEthereumNetwork.EthereumChainConfig.HardForkEpochs] -# hardforks to be applied (fork_name = epoch) -Deneb=500 - -# Chainlink node TOML config -[NodeConfig] -BaseConfigTOML = """ -[Feature] -FeedsManager = true -LogPoller = true -UICSAKeys = true - -[Log] -Level = 'debug' -JSONConsole = true - -[Log.File] -MaxSize = '0b' - -[WebServer] -AllowOrigins = '*' -HTTPPort = 6688 -SecureCookies = false -HTTPWriteTimeout = '3m' -SessionTimeout = '999h0m0s' - -[WebServer.RateLimit] -Authenticated = 2000 -Unauthenticated = 1000 - -[WebServer.TLS] -HTTPSPort = 0 - -[Database] -MaxIdleConns = 20 -MaxOpenConns = 40 -MigrateOnStartup = true - -[OCR2] -Enabled = true - -[P2P] -[P2P.V2] -ListenAddresses = ['0.0.0.0:6690'] -""" - -# override config toml related to EVMNode configs for chainlink nodes; applicable to all EVM node configs in chainlink toml -CommonChainConfigTOML = """ -AutoCreateKey = true -FinalityDepth = 1 -MinContractPayment = 0 - -[GasEstimator] -PriceMax = '200 gwei' -LimitDefault = 6000000 -FeeCapDefault = '200 gwei' -""" - -# chainlink override config toml for EVMNode config specific to EVM chains with chain id as mentioned in the key -[NodeConfig.ChainConfigTOMLByChainID] -# applicable for arbitrum-goerli chain -421613 = """ -[GasEstimator] -PriceMax = '400 gwei' -LimitDefault = 100000000 -FeeCapDefault = '200 gwei' -BumpThreshold = 60 -BumpPercent = 20 -BumpMin = '100 gwei' -""" - -# load test specific configuration -[Load.OCR] -[Load.OCR.Common] -eth_funds = 3 - -[Load.OCR.Load] -test_duration = "3m" -rate_limit_unit_duration = "1m" -rate = 3 -verification_interval = "5s" -verification_timeout = "3m" -ea_change_interval = "5s" - -# soak test specific configuration -[Soak.Common] -chainlink_node_funding = 100 - -[Soak.OCR] -[Soak.OCR.Common] -test_duration="15m" - -[Soak.OCR.Soak] -ocr_version="1" -number_of_contracts=2 -time_between_rounds="1m" \ No newline at end of file diff --git a/integration-tests/testconfig/ocr2vrf/ocr2vrf.toml b/integration-tests/testconfig/ocr2vrf/ocr2vrf.toml deleted file mode 100644 index 884a51736da..00000000000 --- a/integration-tests/testconfig/ocr2vrf/ocr2vrf.toml +++ /dev/null @@ -1,93 +0,0 @@ -# product defaults -[Common] -chainlink_node_funding = 0.5 - -[NodeConfig] -BaseConfigTOML = """ -[Feature] -FeedsManager = true -LogPoller = true -UICSAKeys = true - -[Log] -Level = 'debug' -JSONConsole = true - -[Log.File] -MaxSize = '0b' - -[WebServer] -AllowOrigins = '*' -HTTPPort = 6688 -SecureCookies = false -HTTPWriteTimeout = '3m' -SessionTimeout = '999h0m0s' - -[WebServer.RateLimit] -Authenticated = 2000 -Unauthenticated = 1000 - -[WebServer.TLS] -HTTPSPort = 0 - -[Database] -MaxIdleConns = 20 -MaxOpenConns = 40 -MigrateOnStartup = true - -[OCR2] -Enabled = true - -[P2P] -[P2P.V2] -ListenAddresses = ['0.0.0.0:6690'] -""" - -CommonChainConfigTOML = """ -FinalityDepth = 5 - -[GasEstimator] -LimitDefault = 3_500_000 -PriceMax = 100000000000 -FeeCapDefault = 100000000000 -""" - -# load test specific configuration -[Load.OCR] -[Load.OCR.Common] -eth_funds = 3 - -[Load.OCR.Load] -test_duration = "3m" -rate_limit_unit_duration = "1m" -rate = 3 -verification_interval = "5s" -verification_timeout = "3m" -ea_change_interval = "5s" - -# volume test specific configuration -[Volume.OCR] -[Volume.OCR.Common] -eth_funds = 3 - -[Volume.OCR.Volume] -test_duration = "3m" -rate_limit_unit_duration = "1m" -vu_requests_per_unit = 10 -rate = 1 -verification_interval = "5s" -verification_timeout = "3m" -ea_change_interval = "5s" - -# soak test specific configuration -[Soak.Common] -chainlink_node_funding = 100 - -[Soak.OCR] -[Soak.OCR.Common] -test_duration="15m" - -[Soak.OCR.Soak] -ocr_version="2" -number_of_contracts=2 -time_between_rounds="1m" diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go index 939645306b5..3a73d39dfe9 100644 --- a/integration-tests/testconfig/testconfig.go +++ b/integration-tests/testconfig/testconfig.go @@ -79,12 +79,18 @@ type TestConfig struct { LogPoller *lp_config.Config `toml:"LogPoller"` OCR *ocr_config.Config `toml:"OCR"` OCR2 *ocr_config.Config `toml:"OCR2"` - OCR2VRF *ocr_config.Config `toml:"OCRR2VRF"` VRF *vrf_config.Config `toml:"VRF"` VRFv2 *vrfv2_config.Config `toml:"VRFv2"` VRFv2Plus *vrfv2plus_config.Config `toml:"VRFv2Plus"` + CRIB *CRIB `toml:"CRIB"` - ConfigurationName string `toml:"-"` + ConfigurationNames []string `toml:"-"` +} + +type CRIB struct { + Namespace string `toml:"namespace"` + NetworkName string `toml:"network_name"` + CLNodesNum int `toml:"nodes"` } var embeddedConfigs embed.FS @@ -196,8 +202,8 @@ func (c TestConfig) GetOCRConfig() *ocr_config.Config { return c.OCR } -func (c TestConfig) GetConfigurationName() string { - return c.ConfigurationName +func (c TestConfig) GetConfigurationNames() []string { + return c.ConfigurationNames } func (c TestConfig) GetSethConfig() *seth.Config { @@ -209,11 +215,7 @@ func (c TestConfig) GetActiveOCRConfig() *ocr_config.Config { return c.OCR } - if c.OCR2 != nil { - return c.OCR2 - } - - return c.OCR2VRF + return c.OCR2 } func (c *TestConfig) AsBase64() (string, error) { @@ -251,7 +253,6 @@ const ( Node Product = "node" OCR Product = "ocr" OCR2 Product = "ocr2" - OCR2VRF Product = "ocr2vrf" RunLog Product = "runlog" VRF Product = "vrf" VRFv2 Product = "vrfv2" @@ -271,15 +272,23 @@ func GetConfigurationNameFromEnv() (string, error) { const ( Base64OverrideEnvVarName = k8s_config.EnvBase64ConfigOverride - NoKey = "NO_KEY" ) -func GetConfig(configurationName string, product Product) (TestConfig, error) { +func GetConfig(configurationNames []string, product Product) (TestConfig, error) { logger := logging.GetTestLogger(nil) - configurationName = strings.ReplaceAll(configurationName, "/", "_") - configurationName = strings.ReplaceAll(configurationName, " ", "_") - configurationName = cases.Title(language.English, cases.NoLower).String(configurationName) + for idx, configurationName := range configurationNames { + configurationNames[idx] = strings.ReplaceAll(configurationName, "/", "_") + configurationNames[idx] = strings.ReplaceAll(configurationName, " ", "_") + configurationNames[idx] = cases.Title(language.English, cases.NoLower).String(configurationName) + } + + // add unnamed (default) configuration as the first one to be read + configurationNamesCopy := make([]string, len(configurationNames)) + copy(configurationNamesCopy, configurationNames) + + configurationNames = append([]string{""}, configurationNamesCopy...) + fileNames := []string{ "default.toml", fmt.Sprintf("%s.toml", product), @@ -287,8 +296,9 @@ func GetConfig(configurationName string, product Product) (TestConfig, error) { } testConfig := TestConfig{} - testConfig.ConfigurationName = configurationName - logger.Debug().Msgf("Will apply configuration named '%s' if it is found in any of the configs", configurationName) + testConfig.ConfigurationNames = configurationNames + + logger.Debug().Msgf("Will apply configurations named '%s' if they are found in any of the configs", strings.Join(configurationNames, ",")) // read embedded configs is build tag "embed" is set // this makes our life much easier when using a binary @@ -304,9 +314,11 @@ func GetConfig(configurationName string, product Product) (TestConfig, error) { return TestConfig{}, errors.Wrapf(err, "error reading embedded config") } - err = ctf_config.BytesToAnyTomlStruct(logger, fileName, configurationName, &testConfig, file) - if err != nil { - return TestConfig{}, errors.Wrapf(err, "error unmarshalling embedded config") + for _, configurationName := range configurationNames { + err = ctf_config.BytesToAnyTomlStruct(logger, fileName, configurationName, &testConfig, file) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshalling embedded config %s", embeddedFiles) + } } } } else { @@ -328,9 +340,11 @@ func GetConfig(configurationName string, product Product) (TestConfig, error) { return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) } - err = ctf_config.BytesToAnyTomlStruct(logger, fileName, configurationName, &testConfig, content) - if err != nil { - return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + for _, configurationName := range configurationNames { + err = ctf_config.BytesToAnyTomlStruct(logger, fileName, configurationName, &testConfig, content) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + } } } } @@ -344,9 +358,11 @@ func GetConfig(configurationName string, product Product) (TestConfig, error) { return TestConfig{}, err } - err = ctf_config.BytesToAnyTomlStruct(logger, Base64OverrideEnvVarName, configurationName, &testConfig, decoded) - if err != nil { - return TestConfig{}, errors.Wrapf(err, "error unmarshaling base64 config") + for _, configurationName := range configurationNames { + err = ctf_config.BytesToAnyTomlStruct(logger, Base64OverrideEnvVarName, configurationName, &testConfig, decoded) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshaling base64 config") + } } } else { logger.Debug().Msg("Base64 config override from environment variable not found") @@ -544,12 +560,6 @@ func (c *TestConfig) Validate() error { } } - if c.OCR2VRF != nil { - if err := c.OCR2VRF.Validate(); err != nil { - return errors.Wrapf(err, "OCR2VRF config validation failed") - } - } - if c.VRF != nil { if err := c.VRF.Validate(); err != nil { return errors.Wrapf(err, "VRF config validation failed") diff --git a/integration-tests/testconfig/testconfig_test.go b/integration-tests/testconfig/testconfig_test.go index fd5230dac2d..91d2524fcf0 100644 --- a/integration-tests/testconfig/testconfig_test.go +++ b/integration-tests/testconfig/testconfig_test.go @@ -76,7 +76,7 @@ func TestBase64ConfigRead(t *testing.T) { testConfigEncoded := base64.StdEncoding.EncodeToString(configMarshalled) os.Setenv(Base64OverrideEnvVarName, testConfigEncoded) - readConfig, err := GetConfig("test", Automation) + readConfig, err := GetConfig([]string{"test"}, Automation) require.NoError(t, err, "Error reading config") require.NotNil(t, readConfig.Automation, "Automation config read from base64 is nil") diff --git a/integration-tests/testconfig/testconfig_utils.go b/integration-tests/testconfig/testconfig_utils.go index d4290689bc0..6529771f491 100644 --- a/integration-tests/testconfig/testconfig_utils.go +++ b/integration-tests/testconfig/testconfig_utils.go @@ -68,3 +68,22 @@ selected_networks=` return fmt.Errorf(finalErrStr) } + +func GetChainAndTestTypeSpecificConfig(testType string, product Product) (TestConfig, error) { + config, err := GetConfig([]string{testType}, product) + if err != nil { + return TestConfig{}, fmt.Errorf("error getting config: %w", err) + } + config, err = GetConfig( + []string{ + testType, + config.GetNetworkConfig().SelectedNetworks[0], + fmt.Sprintf("%s-%s", config.GetNetworkConfig().SelectedNetworks[0], testType), + }, + product, + ) + if err != nil { + return TestConfig{}, fmt.Errorf("error getting config: %w", err) + } + return config, err +} diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index 717a62e997f..1d2af760840 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -143,14 +143,6 @@ bhs_test_duration = "10s" bhs_test_rate_limit_unit_duration = "3s" bhs_test_rps = 1 -[Smoke.VRFv2.Performance] -test_duration = "10s" -rate_limit_unit_duration = "3s" -rps = 1 -bhs_test_duration = "10s" -bhs_test_rate_limit_unit_duration = "3s" -bhs_test_rps = 1 - #SOAK TEST CONFIG [Soak.Common] chainlink_node_funding = 0.1 @@ -211,3 +203,650 @@ bhs_test_duration = "1m" bhs_test_rate_limit_unit_duration = "3s" bhs_test_rps = 1 +### POLYGON AMOY Config + +[POLYGON_AMOY.VRFv2Plus.General] +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 3 + +# Consumer Request config +subscription_billing_type = "LINK_AND_NATIVE" +callback_gas_limit = 1000000 + +# NEW ENV CONFIG +# CL Node config +cl_node_max_gas_price_gwei = 200 +number_of_sending_keys_to_create = 0 + +# Coordinator config +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "19823132181656390000" +staleness_seconds = 172_800 +gas_after_payment_calculation = 48_500 +fulfillment_flat_fee_native_ppm = 0 +fulfillment_flat_fee_link_discount_ppm = 0 +native_premium_percentage = 84 +link_premium_percentage = 70 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 99_500 +coordinator_gas_overhead_link = 121_500 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage = 84 +coordinator_link_premium_percentage = 70 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 3.0 +vrf_job_batch_fulfillment_enabled = true +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "2s" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block = "latest" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "2s" +bhs_job_run_timeout = "30s" +# NEW ENV CONFIG END + +[POLYGON_AMOY.VRFv2Plus.ExistingEnv] +coordinator_address = "0x7541EbaE23f32B4A1A2e7a8Cbf9da9582767A9B4" +consumer_address = "" +sub_id = "" +key_hash = "0xd360445bacd26df47086ccf255c4f932d297ed8d5c7334b51eed32f61c541601" +#key_hash = "0x2328cbee29e32d0b6662d6df82ff0fea7be300bd310561c92f515c9ee19464f1" +#key_hash = "0x25f4e2d0509f42ec77db5380f3433a89fe623fa75f65d5b398d5f498327be4dd" +create_fund_subs_and_add_consumers = true +link_address = "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904" +node_sending_key_funding_min = 10 +node_sending_keys = [ + "0xD96013C241f1741C35a135321969f92Aae02A12F", + "0x0580E61a5523F5CAAC4968E4f8FE63b59596BdD7", + "0xd15FcEa6a6AA17085930Fbd5647A9F7fD2Ff58b8", + "0xB7277cBb6E7028AE65235b8ee9201AcBb14B11d4", + "0x6D36a1dC1eEd25C75961E989c4d01Cd4453bE465", + "0xd299Cd7C0073b71e620bf8A3bfD50F75c0b49af8", + "0x48BE7BAED0b65776D85DF971fA901c637cFC5e87", + # BHS + "0x638372de870eF0F8E675A3f67F18D5bd4A2fd804", + "0xF9eF03816411D037202d5ed4457dC1613e3bd729", + "0xCD66973f8fbaE787211EC20228c6bd90D83562A8", + "0x242ea1F4Bb72EF643B2D8EF22e18a89f00742F40", + "0xaA09B4F9B5710b239fdbf1D0f535dd7f86F91219", + "0xe6b72B647B8B45C5562F7a5259E187889C747d3b", + "0x2c1185C4d3B0B4a577d4079Ee193A4e293164D9d" +] + +#SMOKE TEST CONFIG +[POLYGON_AMOY-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5 +subscription_funding_amount_native = 1 +subscription_refunding_amount_link = 5 +subscription_refunding_amount_native = 1 +number_of_words = 1 +random_words_fulfilled_event_timeout = "1m30s" +wait_for_256_blocks_timeout = "15m" + +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 5 + + +[POLYGON_AMOY-Smoke.VRFv2Plus.Performance] +test_duration = "2s" +rate_limit_unit_duration = "15s" +rps = 1 + + +#SOAK TEST CONFIG +[POLYGON_AMOY-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 500 +subscription_funding_amount_native = 200 + +[POLYGON_AMOY-Soak.VRFv2Plus.Performance] +test_duration = "5h" +rate_limit_unit_duration = "3s" +rps = 1 + +# LOAD TEST CONFIG +[POLYGON_AMOY-Load.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 300 +subscription_funding_amount_native = 300 + +[POLYGON_AMOY-Load.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + + +# STRESS TEST CONFIG +[POLYGON_AMOY-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 0.1 + +[POLYGON_AMOY-Stress.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + +### ARBITRUM SEPOLIA Config + +[ARBITRUM_SEPOLIA.VRFv2Plus.General] +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 0 +subscription_billing_type = "LINK_AND_NATIVE" + +cl_node_max_gas_price_gwei = 50 +number_of_sending_keys_to_create = 0 + +# Coordinator config +callback_gas_limit = 1000000 +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "5352799651145251" +staleness_seconds = 172_800 +gas_after_payment_calculation = 56000 +fulfillment_flat_fee_native_ppm=0 +fulfillment_flat_fee_link_discount_ppm=0 +native_premium_percentage=60 +link_premium_percentage=50 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 104_500 +coordinator_gas_overhead_link = 126_500 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage=60 +coordinator_link_premium_percentage=50 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 3.0 +vrf_job_batch_fulfillment_enabled = true +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "300ms" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block="pending" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "300ms" +bhs_job_run_timeout = "30s" +# NEW ENV CONFIG END + +[ARBITRUM_SEPOLIA.VRFv2Plus.ExistingEnv] +coordinator_address = "0xF7ba1Cf141F9729abC43c146dc2bf86EbcfD8603" +consumer_address = "" +sub_id = "" +key_hash = "0xe13aa26fe94bfcd2ae055911f4d3bf1aed54ca6cf77af34e17f918802fd69ba1" +create_fund_subs_and_add_consumers = true +link_address = "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E" +node_sending_key_funding_min = 20 +node_sending_keys = [ + "0xbE21ae371FcA1aC2d8A152e707D21e68d7d99252", + "0xb13e9BA0aE94FD3b89B13b092e6d41614c805134", + "0x27aa703e585Ee165B7c977EAA652eCFa13b08294", + "0x9324643ACD2ec5b0813488E5EdAb64C3758ae4Ee", + "0x7CBA8c8e86f23f23363051650Fe5AE4DE78c3652", + "0x9A0143a4BAB55A826331A8ef82462557633aA016", + "0xD4259633F8e87949F683433a17e1fFcCE27865AC", + "0x5e47B71d6F95f68cd5538907ec6A9635b1Fe30Fa", + "0xa850a1a257FDF439c8f854ce3b89dd5b6F411827", + "0x7c82D56087c10aF2c3970f9a9Be7786B2850ce91", + "0x9545CB59956347d3debf27f5029754bBE1d398FA", + "0xEb8C69ac19709f27A97FB4A561f51AD2F9b34c5B", + # BHS + "0xf0e8cF7Fbd28Fc4D412B76B744CDA269df671F8e", + "0x317A02A658d12E5Bb4A6270171E7385928dD2d53", + "0x480f1dbcEc118Bd91e4dbb7e45bFa4A73180d21f", + "0x500a2662FaF981EC4669f791349D37Cbf1bE7d85", + "0x2ad350374B904c10B47c64ECdBD9e70BB0833Be2", + "0x0b946F0bF4e63C12b5157137f1c130f0788bC1b1", + # BHF + "0x571BBF4a5b07fc3F47Bd3B65CE2FE73739f86623" +] + +#SMOKE TEST CONFIG +[ARBITRUM_SEPOLIA-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5 +subscription_funding_amount_native = 1 +subscription_refunding_amount_link = 20 +subscription_refunding_amount_native = 10 +number_of_words = 1 +random_words_fulfilled_event_timeout = "1m30s" +wait_for_256_blocks_timeout = "100s" + +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 5 + +[ARBITRUM_SEPOLIA-Smoke.VRFv2Plus.Performance] +test_duration = "1s" +rate_limit_unit_duration = "10s" +rps = 1 + + +#SOAK TEST CONFIG +[ARBITRUM_SEPOLIA-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 300 +subscription_funding_amount_native = 100 + +[ARBITRUM_SEPOLIA-Soak.VRFv2Plus.Performance] +test_duration = "1h" +rate_limit_unit_duration = "10s" +rps = 1 + +# LOAD TEST CONFIG +[ARBITRUM_SEPOLIA-Load.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 100 +subscription_funding_amount_native = 60 + +[ARBITRUM_SEPOLIA-Load.VRFv2Plus.Performance] +test_duration = "30m" +rate_limit_unit_duration = "3s" +rps = 1 + + +# STRESS TEST CONFIG +[ARBITRUM_SEPOLIA-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 0.1 + +[ARBITRUM_SEPOLIA-Stress.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + + +### AVALANCHE FUJI Config +[AVALANCHE_FUJI.VRFv2Plus.General] +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 0 + +# Consumer Request config +subscription_billing_type = "LINK_AND_NATIVE" +callback_gas_limit = 1000000 + +# NEW ENV CONFIG +# CL Node config +cl_node_max_gas_price_gwei = 300 +number_of_sending_keys_to_create = 0 + +# Coordinator config +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "378709808510249900" +staleness_seconds = 172_800 +gas_after_payment_calculation = 56_000 +fulfillment_flat_fee_native_ppm = 0 +fulfillment_flat_fee_link_discount_ppm = 0 +native_premium_percentage = 60 +link_premium_percentage = 50 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 107_000 +coordinator_gas_overhead_link = 129_000 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage = 60 +coordinator_link_premium_percentage = 50 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 3.0 +vrf_job_batch_fulfillment_enabled = true +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "2s" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block = "pending" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "2s" +bhs_job_run_timeout = "30s" +# NEW ENV CONFIG END + +[AVALANCHE_FUJI.VRFv2Plus.ExistingEnv] +coordinator_address = "0xE122bf3Badd6545bDec5D4627a6DAd16352A1b36" +consumer_address = "" +sub_id = "" +key_hash = "0x5b03254a80ea3eb72139ff0423cb88be42612780c3dd25f1d95a5ba7708a4be1" +create_fund_subs_and_add_consumers = true +link_address = "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846" +node_sending_key_funding_min = 50 +node_sending_keys = [ + "0x3D7Da5D6A23CA2240CE576C8638C1798a023920a", + # BHS + "0x72c8565279430F5179b0090d51ab8BB53Da323B5" +] + +#SMOKE TEST CONFIG +[AVALANCHE_FUJI-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 20 +subscription_funding_amount_native = 20 +subscription_refunding_amount_link = 20 +subscription_refunding_amount_native = 20 +number_of_words = 1 +random_words_fulfilled_event_timeout = "1m30s" +wait_for_256_blocks_timeout = "10m" + +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 5 + +[AVALANCHE_FUJI-Smoke.VRFv2Plus.Performance] +test_duration = "2s" +rate_limit_unit_duration = "10s" +rps = 1 + + +#SOAK TEST CONFIG +[AVALANCHE_FUJI-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 400 +subscription_funding_amount_native = 200 + +[AVALANCHE_FUJI-Soak.VRFv2Plus.Performance] +test_duration = "5h" +rate_limit_unit_duration = "3s" +rps = 1 + +# LOAD TEST CONFIG +[AVALANCHE_FUJI-Load.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 300 +subscription_funding_amount_native = 300 + +[AVALANCHE_FUJI-Load.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + + +# STRESS TEST CONFIG +[AVALANCHE_FUJI-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 0.1 + +[AVALANCHE_FUJI-Stress.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + +### ETH SEPOLIA Config +[SEPOLIA.VRFv2Plus.General] +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 3 + +# Consumer Request config +subscription_billing_type = "LINK_AND_NATIVE" +callback_gas_limit = 1000000 + +# NEW ENV CONFIG +# CL Node config +cl_node_max_gas_price_gwei = 100 +number_of_sending_keys_to_create = 0 + +# Coordinator config +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "5354747932930759" +staleness_seconds = 172_800 +gas_after_payment_calculation = 38_900 +fulfillment_flat_fee_native_ppm = 0 +fulfillment_flat_fee_link_discount_ppm = 0 +native_premium_percentage = 24 +link_premium_percentage = 20 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 90_000 +coordinator_gas_overhead_link = 112_000 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage = 24 +coordinator_link_premium_percentage = 20 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 1.15 +vrf_job_batch_fulfillment_enabled = false +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "5s" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block = "latest" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "30s" +bhs_job_run_timeout = "1m0s" +# NEW ENV CONFIG END + +[SEPOLIA.VRFv2Plus.ExistingEnv] +coordinator_address = "0x2F3b892710523Ee9A85c3155a42089fFe99Ca31e" +consumer_address = "" +sub_id = "" +key_hash = "0xf5b4a359df0598eef89872ea2170f2afa844dbf74b417e6d44d4bda9420aceb2" +create_fund_subs_and_add_consumers = true +link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789" +node_sending_key_funding_min = 50 +node_sending_keys = [ + "0x0c0DC7f33A1256f0247c5ea75861d385fa5FED31", + # BHS + "0xEd8A4b792d16484f6c9B4df1e721e8280925Db80", +] + +#SMOKE TEST CONFIG +[SEPOLIA-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5 +subscription_funding_amount_native = 1 +subscription_refunding_amount_link = 5 +subscription_refunding_amount_native = 1 +number_of_words = 1 +random_words_fulfilled_event_timeout = "1m30s" +wait_for_256_blocks_timeout = "70m" + +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 5 + +[SEPOLIA-Smoke.VRFv2Plus.Performance] +test_duration = "2s" +rate_limit_unit_duration = "3s" +rps = 1 + +#SOAK TEST CONFIG +[SEPOLIA-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 500 +subscription_funding_amount_native = 200 + +[SEPOLIA-Soak.VRFv2Plus.Performance] +test_duration = "2h" +rate_limit_unit_duration = "3s" +rps = 1 + +# LOAD TEST CONFIG +[SEPOLIA-Load.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 30 + +[SEPOLIA-Load.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + +# STRESS TEST CONFIG +[SEPOLIA-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 0.1 + +[SEPOLIA-Stress.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + +### BSC SEPOLIA Config +[BSC_TESTNET.VRFv2Plus.General] +use_existing_env = true +#todo - need to have separate minimum_confirmations config for Coordinator, CL Node and Consumer request +minimum_confirmations = 3 + +# Consumer Request config +subscription_billing_type = "LINK_AND_NATIVE" +callback_gas_limit = 1000000 + +# NEW ENV CONFIG +# CL Node config +cl_node_max_gas_price_gwei = 50 +number_of_sending_keys_to_create = 0 + +# Coordinator config +max_gas_limit_coordinator_config = 2500000 +fallback_wei_per_unit_link = "30531029880396850" +staleness_seconds = 172_800 +gas_after_payment_calculation = 48_500 +fulfillment_flat_fee_native_ppm = 0 +fulfillment_flat_fee_link_discount_ppm = 0 +native_premium_percentage = 60 +link_premium_percentage = 50 + +# Wrapper config +wrapped_gas_overhead = 13_400 +coordinator_gas_overhead_native = 99_500 +coordinator_gas_overhead_link = 121_500 +coordinator_gas_overhead_per_word = 435 +coordinator_native_premium_percentage = 60 +coordinator_link_premium_percentage = 50 +wrapper_max_number_of_words = 10 + +# VRF Job config +vrf_job_forwarding_allowed = false +vrf_job_estimate_gas_multiplier = 1.1 +vrf_job_batch_fulfillment_enabled = true +vrf_job_batch_fulfillment_gas_multiplier = 1.1 +vrf_job_poll_period = "3s" +vrf_job_request_timeout = "2h0m0s" +vrf_job_simulation_block = "latest" + +# BHS Job config +bhs_job_wait_blocks = 30 +bhs_job_lookback_blocks = 200 +bhs_job_poll_period = "2s" +bhs_job_run_timeout = "30s" +# NEW ENV CONFIG END + +[BSC_TESTNET.VRFv2Plus.ExistingEnv] +coordinator_address = "0x84A477F6ebF33501eE3ACA86fEcB980b1fC99AC2" +consumer_address = "" +sub_id = "" +key_hash = "0x4d43763d3eff849a89cf578a42787baa32132d7a80032125710e95b3972cd214" +create_fund_subs_and_add_consumers = true +link_address = "0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06" +node_sending_key_funding_min = 150 +node_sending_keys = [ + "0x4EE2Cc6D50E8acb6BaEf673B03559525a6c92fB8", + # BHS + "0xAFB44568f7DAc218EA6e1C71c366692ED4758A07" +] + +#SMOKE TEST CONFIG +[BSC_TESTNET-Smoke.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 10 +subscription_funding_amount_native = 10 + +[BSC_TESTNET-Smoke.VRFv2Plus.Performance] +test_duration = "15s" +rate_limit_unit_duration = "3s" +rps = 1 + + +#SOAK TEST CONFIG +[BSC_TESTNET-Soak.VRFv2Plus.General] +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 400 +subscription_funding_amount_native = 200 + +[BSC_TESTNET-Soak.VRFv2Plus.Performance] +test_duration = "5h" +rate_limit_unit_duration = "3s" +rps = 1 + +# LOAD TEST CONFIG +[BSC_TESTNET-Load.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 300 +subscription_funding_amount_native = 300 + +[BSC_TESTNET-Load.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 + + +# STRESS TEST CONFIG +[BSC_TESTNET-Stress.VRFv2Plus.General] +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 +subscription_funding_amount_link = 5.0 +subscription_funding_amount_native = 0.1 + +[BSC_TESTNET-Stress.VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index 81f2ce0edf4..d50355f39b6 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -801,7 +801,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int) { err = actions.DeployMultiCallAndFundDeploymentAddresses(k.chainClient, k.linkToken, upkeep.NumberOfUpkeeps, linkFunds) require.NoError(k.t, err, "Sending link funds to deployment addresses shouldn't fail") - upkeepIds := actions.RegisterUpkeepContractsWithCheckData(k.t, k.chainClient, k.linkToken, linkFunds, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false, false) + upkeepIds := actions.RegisterUpkeepContractsWithCheckData(k.t, k.chainClient, k.linkToken, linkFunds, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false, false, false, nil) k.keeperRegistries[index] = registry k.keeperRegistrars[index] = registrar diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 749ca3beac9..45c334bf69d 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -372,7 +372,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { // Run starts the OCR soak test func (o *OCRSoakTest) Run() { - config, err := tc.GetConfig("soak", tc.OCR) + config, err := tc.GetConfig([]string{"soak"}, tc.OCR) require.NoError(o.t, err, "Error getting config") ctx, cancel := context.WithTimeout(testcontext.Get(o.t), time.Second*5) diff --git a/integration-tests/types/testconfigs.go b/integration-tests/types/testconfigs.go index 58eb1a7c8cf..ee8a614baef 100644 --- a/integration-tests/types/testconfigs.go +++ b/integration-tests/types/testconfigs.go @@ -35,7 +35,7 @@ type KeeperBenchmarkTestConfig interface { ctf_config.GlobalTestConfig tc.CommonTestConfig tc.KeeperTestConfig - ctf_config.NamedConfiguration + ctf_config.NamedConfigurations testreporters.GrafanaURLProvider } diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 7bedef393df..ee4060f7aba 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -13,8 +13,6 @@ import ( "testing" "time" - seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" - geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -28,9 +26,11 @@ import ( "github.com/smartcontractkit/wasp" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_concurrency "github.com/smartcontractkit/chainlink-testing-framework/concurrency" ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" + seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -204,11 +204,6 @@ func randomWait(minMilliseconds, maxMilliseconds int) { time.Sleep(time.Duration(randomMilliseconds) * time.Millisecond) } -type LogEmitterChannel struct { - logsEmitted int - err error -} - // getIntSlice returns a slice of ints of the provided length func getIntSlice(length int) []int { result := make([]int, length) @@ -229,95 +224,6 @@ func getStringSlice(length int) []string { return result } -// emitEvents emits events from the provided log emitter concurrently according to the provided config -func emitEvents(ctx context.Context, l zerolog.Logger, client *seth.Client, logEmitter *contracts.LogEmitter, cfg *lp_config.Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { - address := (*logEmitter).Address().String() - defer wg.Done() - - var executionGroup sync.WaitGroup - - // Atomic counter is used to keep track of the number of logs emitted - var atomicCounter = atomic.Int32{} - - for i := 0; i < *cfg.LoopedConfig.ExecutionCount; i++ { - executionGroup.Add(1) - } - - var emitAllEvents = func() { - defer executionGroup.Done() - current := atomicCounter.Add(1) - - for _, event := range cfg.General.EventsToEmit { - select { - case <-ctx.Done(): - l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") - return - default: - l.Debug().Str("Emitter address", address).Str("Event type", event.Name).Str("index", fmt.Sprintf("%d/%d", current, *cfg.LoopedConfig.ExecutionCount)).Msg("Emitting log from emitter") - var err error - switch event.Name { - case "Log1": - _, err = client.Decode((*logEmitter).EmitLogIntsFromKey(getIntSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) - case "Log2": - _, err = client.Decode((*logEmitter).EmitLogIntsIndexedFromKey(getIntSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) - case "Log3": - _, err = client.Decode((*logEmitter).EmitLogStringsFromKey(getStringSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) - case "Log4": - _, err = client.Decode((*logEmitter).EmitLogIntMultiIndexedFromKey(1, 1, *cfg.General.EventsPerTx, client.AnySyncedKey())) - default: - err = fmt.Errorf("unknown event name: %s", event.Name) - } - - if err != nil { - results <- LogEmitterChannel{ - err: err, - } - return - } - randomWait(*cfg.LoopedConfig.MinEmitWaitTimeMs, *cfg.LoopedConfig.MaxEmitWaitTimeMs) - } - - if (current)%10 == 0 { - l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", current, *cfg.LoopedConfig.ExecutionCount)).Msgf("Emitted all %d events", len(cfg.General.EventsToEmit)) - } - } - } - - clientNumber := int(*client.Cfg.EphemeralAddrs) - emissionsPerClient := *cfg.LoopedConfig.ExecutionCount / clientNumber - extraEmissions := *cfg.LoopedConfig.ExecutionCount % clientNumber - - l.Debug().Str("Emitter address", address). - Int("Total logs to emit", *cfg.LoopedConfig.ExecutionCount*len(cfg.General.EventsToEmit)*(*cfg.General.EventsPerTx)). - Int("Total clients", clientNumber). - Int("Emissions per client", emissionsPerClient). - Int("Extra emissions", extraEmissions). - Msg("Starting to emit events") - - for i := 0; i < clientNumber; i++ { - go func(key int) { - numTasks := emissionsPerClient - if key < extraEmissions { - numTasks++ - } - - for idx := 0; idx < numTasks; idx++ { - emitAllEvents() - } - }(i) - } - - executionGroup.Wait() - - localCounter := int(atomicCounter.Load()) * *cfg.General.EventsPerTx * len(cfg.General.EventsToEmit) - l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") - - results <- LogEmitterChannel{ - logsEmitted: localCounter, - err: nil, - } -} - // LogPollerHasFinalisedEndBlock returns true if all CL nodes have finalised processing the provided end block func LogPollerHasFinalisedEndBlock(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { wg := &sync.WaitGroup{} @@ -699,7 +605,7 @@ func GetMissingLogs(startBlock, endBlock int64, logEmitters []*contracts.LogEmit if int64(len(allLogsInEVMNode)) != expectedTotalLogsEmitted { l.Warn(). Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))). - Msg("Some of the test logs were not found in EVM node. This is a bug in the test") + Msg("Actual number of logs found on EVM nodes differs from expected ones. Most probably this is a bug in the test") } return missingLogs, nil @@ -854,58 +760,89 @@ func runWaspGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contra return counter.value, nil } +type logEmissionTask struct { + emitter *contracts.LogEmitter + eventsToEmit []abi.Event + eventsPerTx int +} + +type emittedLogsData struct { + count int +} + +func (d emittedLogsData) GetResult() emittedLogsData { + return d +} + // runLoopedGenerator runs the looped generator and returns the total number of logs emitted func runLoopedGenerator(t *testing.T, cfg *lp_config.Config, client *seth.Client, logEmitters []*contracts.LogEmitter) (int, error) { l := logging.GetTestLogger(t) - // Start emitting events in parallel, each contract is emitting events in a separate goroutine - // We will stop as soon as we encounter an error - wg := &sync.WaitGroup{} - emitterCh := make(chan LogEmitterChannel, len(logEmitters)) + tasks := make([]logEmissionTask, 0) + for i := 0; i < *cfg.LoopedConfig.ExecutionCount; i++ { + for _, logEmitter := range logEmitters { + tasks = append(tasks, logEmissionTask{ + emitter: logEmitter, + eventsToEmit: cfg.General.EventsToEmit, + eventsPerTx: *cfg.General.EventsPerTx, + }) + } + } - ctx, cancelFn := context.WithCancel(context.Background()) - defer cancelFn() + l.Info().Int("Total tasks", len(tasks)).Msg("Starting to emit events") - for i := 0; i < len(logEmitters); i++ { - wg.Add(1) - go func(idx int) { - emitEvents(ctx, l, client, logEmitters[idx], cfg, wg, emitterCh) - }(i) - } + var atomicCounter = atomic.Int32{} - var emitErr error - total := 0 + var emitAllEventsFn = func(resultCh chan emittedLogsData, errorCh chan error, _ int, task logEmissionTask) { + current := atomicCounter.Add(1) - aggrChan := make(chan int, len(logEmitters)) + address := (*task.emitter).Address().String() - go func() { - for { - select { - case <-ctx.Done(): + for _, event := range cfg.General.EventsToEmit { + l.Debug().Str("Emitter address", address).Str("Event type", event.Name).Str("index", fmt.Sprintf("%d/%d", current, *cfg.LoopedConfig.ExecutionCount)).Msg("Emitting log from emitter") + var err error + switch event.Name { + case "Log1": + _, err = client.Decode((*task.emitter).EmitLogIntsFromKey(getIntSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) + case "Log2": + _, err = client.Decode((*task.emitter).EmitLogIntsIndexedFromKey(getIntSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) + case "Log3": + _, err = client.Decode((*task.emitter).EmitLogStringsFromKey(getStringSlice(*cfg.General.EventsPerTx), client.AnySyncedKey())) + case "Log4": + _, err = client.Decode((*task.emitter).EmitLogIntMultiIndexedFromKey(1, 1, *cfg.General.EventsPerTx, client.AnySyncedKey())) + default: + err = fmt.Errorf("unknown event name: %s", event.Name) + } + + if err != nil { + errorCh <- err return - case emitter := <-emitterCh: - if emitter.err != nil { - emitErr = emitter.err - cancelFn() - return - } - aggrChan <- emitter.logsEmitted + } + randomWait(*cfg.LoopedConfig.MinEmitWaitTimeMs, *cfg.LoopedConfig.MaxEmitWaitTimeMs) + + if (current)%10 == 0 { + l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", current, *cfg.LoopedConfig.ExecutionCount)).Msgf("Emitted all %d events", len(cfg.General.EventsToEmit)) } } - }() - wg.Wait() - close(emitterCh) + resultCh <- emittedLogsData{ + *cfg.General.EventsPerTx * len(cfg.General.EventsToEmit), + } + } + + executor := ctf_concurrency.NewConcurrentExecutor[emittedLogsData, emittedLogsData, logEmissionTask](l) + r, err := executor.Execute(int(*client.Cfg.EphemeralAddrs), tasks, emitAllEventsFn) - if emitErr != nil { - return 0, emitErr + if err != nil { + return 0, err } - for i := 0; i < len(logEmitters); i++ { - total += <-aggrChan + var total int + for _, result := range r { + total += result.count } - return int(total), nil + return total, nil } // GetExpectedLogCount returns the expected number of logs to be emitted based on the provided config diff --git a/operator_ui/TAG b/operator_ui/TAG index 57ed352173b..bd6882b0f5c 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-7e6a14f +v0.8.0-094d250 diff --git a/package.json b/package.json index f12e869542b..b60a4573d5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chainlink", - "version": "2.13.0", + "version": "2.14.0", "description": "node of the decentralized oracle network, bridging on and off-chain computation", "main": "index.js", "scripts": { diff --git a/testdata/scripts/help-all/help-all.txtar b/testdata/scripts/help-all/help-all.txtar index e111295abb4..372b149bd19 100644 --- a/testdata/scripts/help-all/help-all.txtar +++ b/testdata/scripts/help-all/help-all.txtar @@ -55,6 +55,12 @@ jobs list # List all jobs jobs run # Trigger a job run jobs show # Show a job keys # Commands for managing various types of keys used by the Chainlink node +keys aptos # Remote commands for administering the node's Aptos keys +keys aptos create # Create a Aptos key +keys aptos delete # Delete Aptos key if present +keys aptos export # Export Aptos key to keyfile +keys aptos import # Import Aptos key from keyfile +keys aptos list # List the Aptos keys keys cosmos # Remote commands for administering the node's Cosmos keys keys cosmos create # Create a Cosmos key keys cosmos delete # Delete Cosmos key if present @@ -66,18 +72,6 @@ keys csa create # Create a CSA key, encrypted with password from the password fi keys csa export # Exports an existing CSA key by its ID. keys csa import # Imports a CSA key from a JSON file. keys csa list # List available CSA keys -keys dkgencrypt # Remote commands for administering the node's DKGEncrypt keys -keys dkgencrypt create # Create a DKGEncrypt key -keys dkgencrypt delete # Delete DKGEncrypt key if present -keys dkgencrypt export # Export DKGEncrypt key to keyfile -keys dkgencrypt import # Import DKGEncrypt key from keyfile -keys dkgencrypt list # List the DKGEncrypt keys -keys dkgsign # Remote commands for administering the node's DKGSign keys -keys dkgsign create # Create a DKGSign key -keys dkgsign delete # Delete DKGSign key if present -keys dkgsign export # Export DKGSign key to keyfile -keys dkgsign import # Import DKGSign key from keyfile -keys dkgsign list # List the DKGSign keys keys eth # Remote commands for administering the node's Ethereum keys keys eth chain # Update an EVM key for the given chain keys eth create # Create a key in the node's keystore alongside the existing key; to create an original key, just run the node diff --git a/testdata/scripts/keys/aptos/help.txtar b/testdata/scripts/keys/aptos/help.txtar new file mode 100644 index 00000000000..94f0c7db8c3 --- /dev/null +++ b/testdata/scripts/keys/aptos/help.txtar @@ -0,0 +1,20 @@ +exec chainlink keys aptos --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink keys aptos - Remote commands for administering the node's Aptos keys + +USAGE: + chainlink keys aptos command [command options] [arguments...] + +COMMANDS: + create Create a Aptos key + import Import Aptos key from keyfile + export Export Aptos key to keyfile + delete Delete Aptos key if present + list List the Aptos keys + +OPTIONS: + --help, -h show help + diff --git a/testdata/scripts/keys/dkgencrypt/help.txtar b/testdata/scripts/keys/dkgencrypt/help.txtar deleted file mode 100644 index 98a791eccf0..00000000000 --- a/testdata/scripts/keys/dkgencrypt/help.txtar +++ /dev/null @@ -1,20 +0,0 @@ -exec chainlink keys dkgencrypt --help -cmp stdout out.txt - --- out.txt -- -NAME: - chainlink keys dkgencrypt - Remote commands for administering the node's DKGEncrypt keys - -USAGE: - chainlink keys dkgencrypt command [command options] [arguments...] - -COMMANDS: - create Create a DKGEncrypt key - import Import DKGEncrypt key from keyfile - export Export DKGEncrypt key to keyfile - delete Delete DKGEncrypt key if present - list List the DKGEncrypt keys - -OPTIONS: - --help, -h show help - diff --git a/testdata/scripts/keys/dkgsign/help.txtar b/testdata/scripts/keys/dkgsign/help.txtar deleted file mode 100644 index 7c3e2258423..00000000000 --- a/testdata/scripts/keys/dkgsign/help.txtar +++ /dev/null @@ -1,20 +0,0 @@ -exec chainlink keys dkgsign --help -cmp stdout out.txt - --- out.txt -- -NAME: - chainlink keys dkgsign - Remote commands for administering the node's DKGSign keys - -USAGE: - chainlink keys dkgsign command [command options] [arguments...] - -COMMANDS: - create Create a DKGSign key - import Import DKGSign key from keyfile - export Export DKGSign key to keyfile - delete Delete DKGSign key if present - list List the DKGSign keys - -OPTIONS: - --help, -h show help - diff --git a/testdata/scripts/keys/help.txtar b/testdata/scripts/keys/help.txtar index a54002e272b..83253d6906d 100644 --- a/testdata/scripts/keys/help.txtar +++ b/testdata/scripts/keys/help.txtar @@ -9,17 +9,16 @@ USAGE: chainlink keys command [command options] [arguments...] COMMANDS: - eth Remote commands for administering the node's Ethereum keys - p2p Remote commands for administering the node's p2p keys - csa Remote commands for administering the node's CSA keys - ocr Remote commands for administering the node's legacy off chain reporting keys - ocr2 Remote commands for administering the node's off chain reporting keys - cosmos Remote commands for administering the node's Cosmos keys - solana Remote commands for administering the node's Solana keys - starknet Remote commands for administering the node's StarkNet keys - dkgsign Remote commands for administering the node's DKGSign keys - dkgencrypt Remote commands for administering the node's DKGEncrypt keys - vrf Remote commands for administering the node's vrf keys + eth Remote commands for administering the node's Ethereum keys + p2p Remote commands for administering the node's p2p keys + csa Remote commands for administering the node's CSA keys + ocr Remote commands for administering the node's legacy off chain reporting keys + ocr2 Remote commands for administering the node's off chain reporting keys + cosmos Remote commands for administering the node's Cosmos keys + solana Remote commands for administering the node's Solana keys + starknet Remote commands for administering the node's StarkNet keys + aptos Remote commands for administering the node's Aptos keys + vrf Remote commands for administering the node's vrf keys OPTIONS: --help, -h show help diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 6e2a40beb7f..e8e1046cef5 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -330,6 +330,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -384,6 +385,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [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 5db4e8527d3..c7b651e3aeb 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -330,6 +330,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -384,6 +385,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [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 bcf054cbca3..1eee9f595c3 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -330,6 +330,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -384,6 +385,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 6b5932cfefd..73d557c0ae7 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -320,6 +320,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -374,6 +375,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 688829513e9..76a134b7761 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -327,6 +327,7 @@ NoNewHeadsThreshold = '3m0s' OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A' RPCDefaultBatchSize = 250 RPCBlockQueryDelay = 1 +FinalizedBlockOffset = 0 [EVM.Transactions] ForwardersEnabled = false @@ -381,6 +382,8 @@ SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false FinalizedBlockPollInterval = '5s' +EnforceRepeatableRead = false +DeathDeclarationDelay = '10s' [EVM.OCR] ContractConfirmations = 4